get rid of EOL spaces
[pandora-libraries.git] / lib / pnd_utility.c
1
2 #include <stdio.h> /* for FILE etc */
3 #include <stdlib.h> /* for malloc */
4 #define __USE_GNU /* for strcasestr */
5 #include <string.h> /* for making ftw.h happy */
6 #include <unistd.h> /* for fork exec */
7
8 #include <utmp.h> /* for expand-tilde below; see commentary for this about-turn */
9 #include <sys/types.h> /* ditto */
10 #include <pwd.h> /* ditto */
11 #include <sys/stat.h> /* for fstat */
12 #include <dirent.h> /* for opendir */
13
14 #include "pnd_pxml.h"
15 #include "pnd_container.h"
16 #include "pnd_utility.h"
17 #include "pnd_pndfiles.h"
18 #include "pnd_discovery.h"
19
20 unsigned char pnd_check_login ( char *r_username, unsigned int maxlen ) {
21   FILE *f;
22   struct utmp b;
23   struct passwd *pw;
24
25   f = fopen ( "/var/run/utmp", "r" );
26
27   if ( f ) {
28
29     // spin until a non-root user comes along
30     while ( fread ( &b, sizeof(struct utmp), 1, f ) == 1 ) {
31
32       if ( ( b.ut_type == USER_PROCESS ) &&
33            ( strcmp ( b.ut_user, "root" ) != 0 ) )
34       {
35
36         // ut_user contains the username ..
37         // now we need to find the path to that account.
38         while ( ( pw = getpwent() ) ) {
39
40           if ( strcmp ( pw -> pw_name, b.ut_user ) == 0 ) {
41
42             if ( r_username ) {
43               strncpy ( r_username, b.ut_user, maxlen );
44             }
45
46             fclose ( f );
47             return ( 1 );
48           } // passwd entry matches the utmp entry
49
50         } // while iteratin across passwd entries
51         endpwent();
52
53       } // utmp entry is for a user login
54
55     } // while
56
57     fclose ( f );
58   } // opened?
59
60   return ( 0 );
61 }
62
63 // a generalized variable-substitution routine might be nice; for now we need a quick tilde one,
64 // so here goes. Brute force ftw!
65 char *pnd_expand_tilde ( char *freeable_buffer ) {
66   char *p;
67   char *s = freeable_buffer;
68   char *home = getenv ( "HOME" );
69
70   //printf ( "DEBUG: expand tilde IN: '%s'\n", freeable_buffer );
71   //printf ( "DEBUG:  $HOME was %s\n", home );
72
73   // well, as pndnotifyd (etc) may be running as _root_, while the user is logged in
74   // as 'pandora' or god knows what, this could be problematic. Other parts of the lib
75   // use wordexp() for shell-like expansion, but this funciton is (at least) used by
76   // pndnotifyd for determination of the .desktop emit path, so we need ~ to expand
77   // to the _actual user_ rather than root's homedir. Rather than run 'users' or 'who'
78   // or the like, we'll just cut to the chase..
79   ///////
80   {
81     FILE *f;
82     struct utmp b;
83     static char *florp = NULL;
84     struct passwd *pw;
85
86     f = fopen ( "/var/run/utmp", "r" );
87
88     if ( f ) {
89
90       while ( fread ( &b, sizeof(struct utmp), 1, f ) == 1 ) {
91
92         if ( b.ut_type == USER_PROCESS ) {
93
94           // ut_user contains the username ..
95           // now we need to find the path to that account.
96           while ( ( pw = getpwent() ) ) {
97
98             if ( strcmp ( pw -> pw_name, b.ut_user ) == 0 ) {
99
100               // aight, we've got a logged in user and have matched it to
101               // passwd entry, so can construct the appropriate path
102
103               if ( florp ) {
104                 free ( florp );
105               }
106               florp = strdup ( pw -> pw_dir );
107
108               home = florp;
109               //printf ( "  DEBUG: home (for %s) is %s (from %u)\n", b.ut_user, home, b.ut_type );
110
111             } // passwd entry matches the utmp entry
112
113           } // while iteratin across passwd entries
114           endpwent();
115
116         } // utmp entry is for a user login
117
118       } // while
119       fclose ( f );
120     } // opened?
121
122   }
123   ///////
124
125   if ( ! home ) {
126     return ( s ); // can't succeed
127   }
128
129   //printf ( "DEBUG: entering while (%s) with home (%s)\n", s, home );
130
131   while ( ( p = strchr ( s, '~' ) ) ) {
132     //printf ( "DEBUG: within while (%s)\n", s );
133     char *temp = malloc ( strlen ( s ) + strlen ( home ) + 1 );
134     memset ( temp, '\0', strlen ( s ) + strlen ( home ) + 1 );
135     // copy in stuff prior to ~
136     strncpy ( temp, s, p - s );
137     // copy tilde in
138     strcat ( temp, home );
139     // copy stuff after tilde in
140     strcat ( temp, p + 1 );
141     // swap ptrs
142     free ( s );
143     s = temp;
144   } // while finding matches
145
146   //printf ( "DEBUG: expand tilde OUT: '%s'\n", s );
147
148   return ( s );
149 }
150
151 void pnd_exec_no_wait_1 ( char *fullpath, char *arg1 ) {
152   int i;
153
154   if ( ( i = fork() ) < 0 ) {
155     printf ( "ERROR: Couldn't fork()\n" );
156     return;
157   }
158
159   if ( i ) {
160     return; // parent process, don't care
161   }
162
163   // child process, do something
164   if ( arg1 ) {
165     execl ( fullpath, fullpath, arg1, (char*) NULL );
166   } else {
167     execl ( fullpath, fullpath, (char*) NULL );
168   }
169
170   // error invoking something, and we're the child process, so just die before all hell breaks lose with us thinking we're the (second!) parent on return!
171   exit ( -1 );
172
173   // getting here is an error
174   //printf ( "Error attempting to run %s\n", fullpath );
175
176   return;
177 }
178
179 pnd_pxml_handle *pnd_pxml_get_by_path ( char *fullpath ) {
180   unsigned char valid = pnd_object_type_unknown;
181   pnd_pxml_handle *pxmlapps = 0;
182
183   // WARN: this is way too close to callback in pnd_disco .. should be refactored!
184
185   if ( strcasestr ( fullpath, PXML_FILENAME ) ) {
186     valid = pnd_object_type_directory;
187   } else if ( strcasestr ( fullpath, PND_PACKAGE_FILEEXT "\0" ) ) {
188     valid = pnd_object_type_pnd;
189   }
190
191   // if not a file of interest, just keep looking until we run out
192   if ( ! valid ) {
193     return ( 0 );
194   }
195
196   // potentially a valid application
197   if ( valid == pnd_object_type_directory ) {
198     pxmlapps = pnd_pxml_fetch ( (char*) fullpath );
199
200   } else if ( valid == pnd_object_type_pnd ) {
201     FILE *f;
202     char pxmlbuf [ 32 * 1024 ]; // TBD: assuming 32k pxml accrual buffer is a little lame
203
204     // open it up..
205     f = fopen ( fullpath, "r" );
206
207     // try to locate the PXML portion
208     if ( ! pnd_pnd_seek_pxml ( f ) ) {
209       fclose ( f );
210       return ( 0 ); // pnd or not, but not to spec. Pwn'd the pnd?
211     }
212
213     // accrue it into a buffer
214     if ( ! pnd_pnd_accrue_pxml ( f, pxmlbuf, 32 * 1024 ) ) {
215       fclose ( f );
216       return ( 0 );
217     }
218
219     // by now, we have <PXML> .. </PXML>, try to parse..
220     pxmlapps = pnd_pxml_fetch_buffer ( (char*) fullpath, pxmlbuf );
221
222     // done with file
223     fclose ( f );
224
225   }
226
227   // ..
228
229   return ( pxmlapps );
230 }
231
232 unsigned char pnd_determine_mountpoint ( char *fullpath, char *r_mountpoint, unsigned int mountpoint_len ) {
233
234   // just cheap it, and call df like an idiot.
235
236   // Filesystem           1K-blocks      Used Available Use% Mounted on
237
238   char cmd [ PATH_MAX ];
239   FILE *p;
240   char inbuf [ PATH_MAX ];
241
242   sprintf ( cmd, "/bin/df %s 2>/dev/null", fullpath );
243
244   if ( ( p = popen ( cmd, "r" ) ) ) {
245
246     // ignore title line; we really shoudl analyze it to figure out which column, but we make assumptions..
247     fgets ( inbuf, PATH_MAX, p );
248
249     if ( ! fgets ( inbuf, PATH_MAX, p ) ) {
250       pclose ( p );
251       return ( 0 );
252     }
253
254     pclose ( p );
255
256     // by now, good
257     char mount [ PATH_MAX ];
258     if ( sscanf ( inbuf, "%*s %*s %*s %*s %*s %s", mount ) != 1 ) {
259       return ( 0 );
260     }
261
262     if ( strlen ( mount ) < mountpoint_len ) {
263       strcpy ( r_mountpoint, mount );
264       return ( 1 );
265     }
266
267   } // if popen
268
269   return ( 0 );
270
271 #if 0
272   struct stat fooby;
273
274   // can we even stat this file?
275   if ( stat ( fullpath, &fooby ) == 0 ) {
276     //dev_t     st_dev;     /* ID of device containing file */
277     //dev_t     st_rdev;    /* device ID (if special file) */
278
279     dev_t mount = fooby.st_dev;
280
281     DIR *d = opendir ( "/dev" );
282
283     if ( d ) {
284       struct dirent *de;
285       char path [ FILENAME_MAX ];
286
287       while ( de = readdir ( d ) ) {
288         sprintf ( path, "/dev/%s", de -> d_name );
289
290         if ( stat ( path, &fooby ) == 0 ) {
291
292           // finally, if we find the same major/minor pair in /dev, as we found for the target file, it means we found the right device
293           if ( fooby.st_rdev == mount ) {
294             printf ( "Device: %s\n", path );
295           }
296
297         } // if
298
299       } // while
300
301     } // opened /dev?
302
303   } // stat
304 #endif
305
306   return ( 0 );
307 }
308
309 unsigned char pnd_filecopy ( char *sourcepath, char *targetpath ) {
310 #define BITLEN (64*1024)
311   FILE *pnd, *target; // pnd == from, since I cribbed the code from pnd_desktop.c :/
312   unsigned char bits [ BITLEN ];
313   unsigned int bitlen;
314
315   pnd = fopen ( sourcepath, "rb" );
316
317   if ( ! pnd ) {
318     return ( 0 );
319   }
320
321   unsigned int len;
322
323   target = fopen ( targetpath, "wb" );
324
325   if ( ! target ) {
326     fclose ( pnd );
327     return ( 0 );
328   }
329
330   fseek ( pnd, 0, SEEK_END );
331   len = ftell ( pnd );
332   fseek ( pnd, 0, SEEK_SET );
333
334   while ( len ) {
335
336     if ( len > (BITLEN) ) {
337       bitlen = (BITLEN);
338     } else {
339       bitlen = len;
340     }
341
342     if ( fread ( bits, bitlen, 1, pnd ) != 1 ) {
343       fclose ( pnd );
344       fclose ( target );
345       unlink ( targetpath );
346       return ( 0 );
347     }
348
349     if ( fwrite ( bits, bitlen, 1, target ) != 1 ) {
350       fclose ( pnd );
351       fclose ( target );
352       unlink ( targetpath );
353       return ( 0 );
354     }
355
356     len -= bitlen;
357   } // while
358
359   fclose ( pnd );
360   fclose ( target );
361
362   return ( 1 );
363 }