Merge branch 'master' of git://git.openpandora.org/pandora-libraries
[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
12 #include "pnd_pxml.h"
13 #include "pnd_container.h"
14 #include "pnd_utility.h"
15 #include "pnd_pndfiles.h"
16 #include "pnd_discovery.h"
17
18 // a generalized variable-substitution routine might be nice; for now we need a quick tilde one,
19 // so here goes. Brute force ftw!
20 char *pnd_expand_tilde ( char *freeable_buffer ) {
21   char *p;
22   char *s = freeable_buffer;
23   char *home = getenv ( "HOME" );
24
25   //printf ( "expand tilde IN: '%s'\n", freeable_buffer );
26   //printf ( "  home was %s\n", home );
27
28   // well, as pndnotifyd (etc) may be running as _root_, while the user is logged in
29   // as 'pandora' or god knows what, this could be problematic. Other parts of the lib
30   // use wordexp() for shell-like expansion, but this funciton is (at least) used by
31   // pndnotifyd for determination of the .desktop emit path, so we need ~ to expand
32   // to the _actual user_ rather than root's homedir. Rather than run 'users' or 'who'
33   // or the like, we'll just cut to the chase..
34   ///////
35   {
36     FILE *f;
37     struct utmp b;
38     static char *florp = NULL;
39     struct passwd *pw;
40
41     f = fopen ( "/var/run/utmp", "r" );
42
43     if ( f ) {
44
45       while ( fread ( &b, sizeof(struct utmp), 1, f ) == 1 ) {
46
47         if ( b.ut_type == USER_PROCESS ) {
48
49           // ut_user contains the username ..
50           // now we need to find the path to that account.
51           while ( ( pw = getpwent() ) ) {
52
53             if ( strcmp ( pw -> pw_name, b.ut_user ) == 0 ) {
54
55               // aight, we've got a logged in user and have matched it to
56               // passwd entry, so can construct the appropriate path
57
58               if ( florp ) {
59                 free ( florp );
60               }
61               florp = strdup ( pw -> pw_dir );
62
63               home = florp;
64               //printf ( "  home is %s (from %u)\n", home, b.ut_type );
65
66             } // passwd entry matches the utmp entry
67
68           } // while iteratin across passwd entries
69           endpwent();
70
71         } // utmp entry is for a user login
72
73       } // while
74       fclose ( f );
75     } // opened?
76
77   }
78   ///////
79
80   if ( ! home ) {
81     return ( s ); // can't succeed
82   }
83
84   while ( ( p = strchr ( s, '~' ) ) ) {
85     char *temp = malloc ( strlen ( s ) + strlen ( home ) + 1 );
86     memset ( temp, '\0', strlen ( s ) + strlen ( home ) + 1 );
87     // copy in stuff prior to ~
88     strncpy ( temp, s, p - s );
89     // copy tilde in
90     strcat ( temp, home );
91     // copy stuff after tilde in
92     strcat ( temp, p + 1 );
93     // swap ptrs
94     free ( s );
95     s = temp;
96   } // while finding matches
97
98   //printf ( "expand tilde OUT: '%s'\n", s );
99
100   return ( s );
101 }
102
103 void pnd_exec_no_wait_1 ( char *fullpath, char *arg1 ) {
104   int i;
105
106   if ( ( i = fork() ) < 0 ) {
107     printf ( "ERROR: Couldn't fork()\n" );
108     return;
109   }
110
111   if ( i ) {
112     return; // parent process, don't care
113   }
114
115   // child process, do something
116   if ( arg1 ) {
117     execl ( fullpath, fullpath, arg1, (char*) NULL );
118   } else {
119     execl ( fullpath, fullpath, (char*) NULL );
120   }
121
122   // getting here is an error
123   //printf ( "Error attempting to run %s\n", fullpath );
124
125   return;
126 }
127
128 pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath ) {
129   unsigned char valid = pnd_object_type_unknown;
130   pnd_pxml_handle pxmlh = 0;
131
132   // WARN: this is way too close to callback in pnd_disco .. should be refactored!
133
134   if ( strcasestr ( fullpath, PXML_FILENAME ) ) {
135     valid = pnd_object_type_directory;
136   } else if ( strcasestr ( fullpath, PND_PACKAGE_FILEEXT "\0" ) ) {
137     valid = pnd_object_type_pnd;
138   }
139
140   // if not a file of interest, just keep looking until we run out
141   if ( ! valid ) {
142     return ( 0 );
143   }
144
145   // potentially a valid application
146   if ( valid == pnd_object_type_directory ) {
147     pxmlh = pnd_pxml_fetch ( (char*) fullpath );
148
149   } else if ( valid == pnd_object_type_pnd ) {
150     FILE *f;
151     char pxmlbuf [ 32 * 1024 ]; // TBD: assuming 32k pxml accrual buffer is a little lame
152
153     // open it up..
154     f = fopen ( fullpath, "r" );
155
156     // try to locate the PXML portion
157     if ( ! pnd_pnd_seek_pxml ( f ) ) {
158       fclose ( f );
159       return ( 0 ); // pnd or not, but not to spec. Pwn'd the pnd?
160     }
161
162     // accrue it into a buffer
163     if ( ! pnd_pnd_accrue_pxml ( f, pxmlbuf, 32 * 1024 ) ) {
164       fclose ( f );
165       return ( 0 );
166     }
167
168     // by now, we have <PXML> .. </PXML>, try to parse..
169     pxmlh = pnd_pxml_fetch_buffer ( (char*) fullpath, pxmlbuf );
170
171     // done with file
172     fclose ( f );
173
174   }
175
176   // ..
177
178   return ( pxmlh );
179 }