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 */
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 <errno.h> /* for stat->ENOENT */
13 #include <dirent.h> /* for opendir */
14 #include <fcntl.h> /* for creat */
17 #include "pnd_container.h"
18 #include "pnd_utility.h"
19 #include "pnd_pndfiles.h"
20 #include "pnd_discovery.h"
22 unsigned char pnd_check_login ( char *r_username, unsigned int maxlen ) {
27 f = fopen ( "/var/run/utmp", "r" );
31 // spin until a non-root user comes along
32 while ( fread ( &b, sizeof(struct utmp), 1, f ) == 1 ) {
34 if ( ( b.ut_type == USER_PROCESS ) &&
35 ( strcmp ( b.ut_user, "root" ) != 0 ) )
38 // ut_user contains the username ..
39 // now we need to find the path to that account.
40 while ( ( pw = getpwent() ) ) {
42 if ( strcmp ( pw -> pw_name, b.ut_user ) == 0 ) {
45 strncpy ( r_username, b.ut_user, maxlen );
50 } // passwd entry matches the utmp entry
52 } // while iteratin across passwd entries
55 } // utmp entry is for a user login
65 // a generalized variable-substitution routine might be nice; for now we need a quick tilde one,
66 // so here goes. Brute force ftw!
67 char *pnd_expand_tilde ( char *freeable_buffer ) {
69 char *s = freeable_buffer;
70 char *home = getenv ( "HOME" );
72 //printf ( "DEBUG: expand tilde IN: '%s'\n", freeable_buffer );
73 //printf ( "DEBUG: $HOME was %s\n", home );
75 // well, as pndnotifyd (etc) may be running as _root_, while the user is logged in
76 // as 'pandora' or god knows what, this could be problematic. Other parts of the lib
77 // use wordexp() for shell-like expansion, but this funciton is (at least) used by
78 // pndnotifyd for determination of the .desktop emit path, so we need ~ to expand
79 // to the _actual user_ rather than root's homedir. Rather than run 'users' or 'who'
80 // or the like, we'll just cut to the chase..
85 static char *florp = NULL;
88 f = fopen ( "/var/run/utmp", "r" );
92 while ( fread ( &b, sizeof(struct utmp), 1, f ) == 1 ) {
94 if ( b.ut_type == USER_PROCESS ) {
96 // ut_user contains the username ..
97 // now we need to find the path to that account.
98 while ( ( pw = getpwent() ) ) {
100 if ( strcmp ( pw -> pw_name, b.ut_user ) == 0 ) {
102 // aight, we've got a logged in user and have matched it to
103 // passwd entry, so can construct the appropriate path
108 florp = strdup ( pw -> pw_dir );
111 //printf ( " DEBUG: home (for %s) is %s (from %u)\n", b.ut_user, home, b.ut_type );
113 } // passwd entry matches the utmp entry
115 } // while iteratin across passwd entries
118 } // utmp entry is for a user login
128 return ( s ); // can't succeed
131 //printf ( "DEBUG: entering while (%s) with home (%s)\n", s, home );
133 while ( ( p = strchr ( s, '~' ) ) ) {
134 //printf ( "DEBUG: within while (%s)\n", s );
135 char *temp = malloc ( strlen ( s ) + strlen ( home ) + 1 );
136 memset ( temp, '\0', strlen ( s ) + strlen ( home ) + 1 );
137 // copy in stuff prior to ~
138 strncpy ( temp, s, p - s );
140 strcat ( temp, home );
141 // copy stuff after tilde in
142 strcat ( temp, p + 1 );
146 } // while finding matches
148 //printf ( "DEBUG: expand tilde OUT: '%s'\n", s );
153 void pnd_exec_no_wait_1 ( char *fullpath, char *arg1 ) {
156 if ( ( i = fork() ) < 0 ) {
157 printf ( "ERROR: Couldn't fork()\n" );
162 return; // parent process, don't care
165 // child process, do something
167 execl ( fullpath, fullpath, arg1, (char*) NULL );
169 execl ( fullpath, fullpath, (char*) NULL );
172 // 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!
175 // getting here is an error
176 //printf ( "Error attempting to run %s\n", fullpath );
181 pnd_pxml_handle *pnd_pxml_get_by_path ( char *fullpath ) {
182 unsigned char valid = pnd_object_type_unknown;
183 pnd_pxml_handle *pxmlapps = 0;
185 // WARN: this is way too close to callback in pnd_disco .. should be refactored!
187 if ( strcasestr ( fullpath, PXML_FILENAME ) ) {
188 valid = pnd_object_type_directory;
189 } else if ( strcasestr ( fullpath, PND_PACKAGE_FILEEXT "\0" ) ) {
190 valid = pnd_object_type_pnd;
193 // if not a file of interest, just keep looking until we run out
198 // potentially a valid application
199 if ( valid == pnd_object_type_directory ) {
200 pxmlapps = pnd_pxml_fetch ( (char*) fullpath );
202 } else if ( valid == pnd_object_type_pnd ) {
204 char pxmlbuf [ 32 * 1024 ]; // TBD: assuming 32k pxml accrual buffer is a little lame
207 f = fopen ( fullpath, "r" );
209 // try to locate the PXML portion
210 if ( ! pnd_pnd_seek_pxml ( f ) ) {
212 return ( 0 ); // pnd or not, but not to spec. Pwn'd the pnd?
215 // accrue it into a buffer
216 if ( ! pnd_pnd_accrue_pxml ( f, pxmlbuf, 32 * 1024 ) ) {
221 // by now, we have <PXML> .. </PXML>, try to parse..
222 pxmlapps = pnd_pxml_fetch_buffer ( (char*) fullpath, pxmlbuf );
234 unsigned char pnd_determine_mountpoint ( char *fullpath, char *r_mountpoint, unsigned int mountpoint_len ) {
236 // just cheap it, and call df like an idiot.
238 // Filesystem 1K-blocks Used Available Use% Mounted on
240 char cmd [ PATH_MAX ];
242 char inbuf [ PATH_MAX ];
244 sprintf ( cmd, "/bin/df %s 2>/dev/null", fullpath );
246 if ( ( p = popen ( cmd, "r" ) ) ) {
248 // ignore title line; we really shoudl analyze it to figure out which column, but we make assumptions..
249 fgets ( inbuf, PATH_MAX, p );
251 if ( ! fgets ( inbuf, PATH_MAX, p ) ) {
259 char mount [ PATH_MAX ];
260 if ( sscanf ( inbuf, "%*s %*s %*s %*s %*s %s", mount ) != 1 ) {
264 if ( strlen ( mount ) < mountpoint_len ) {
265 strcpy ( r_mountpoint, mount );
276 // can we even stat this file?
277 if ( stat ( fullpath, &fooby ) == 0 ) {
278 //dev_t st_dev; /* ID of device containing file */
279 //dev_t st_rdev; /* device ID (if special file) */
281 dev_t mount = fooby.st_dev;
283 DIR *d = opendir ( "/dev" );
287 char path [ FILENAME_MAX ];
289 while ( de = readdir ( d ) ) {
290 sprintf ( path, "/dev/%s", de -> d_name );
292 if ( stat ( path, &fooby ) == 0 ) {
294 // 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
295 if ( fooby.st_rdev == mount ) {
296 printf ( "Device: %s\n", path );
311 unsigned char pnd_filecopy ( char *sourcepath, char *targetpath ) {
312 #define BITLEN (64*1024)
313 FILE *pnd, *target; // pnd == from, since I cribbed the code from pnd_desktop.c :/
314 unsigned char bits [ BITLEN ];
317 pnd = fopen ( sourcepath, "rb" );
325 target = fopen ( targetpath, "wb" );
332 fseek ( pnd, 0, SEEK_END );
334 fseek ( pnd, 0, SEEK_SET );
338 if ( len > (BITLEN) ) {
344 if ( fread ( bits, bitlen, 1, pnd ) != 1 ) {
347 unlink ( targetpath );
351 if ( fwrite ( bits, bitlen, 1, target ) != 1 ) {
354 unlink ( targetpath );
367 unsigned char pnd_lock ( char *lockname ) {
369 if ( pnd_is_locked ( lockname ) ) {
370 return ( 0 ); // already locked
373 char fullpath [ PATH_MAX ];
376 snprintf ( fullpath, PATH_MAX, "%s/%s", PND_LOCK_PATH, lockname );
378 if ( ( fd = creat ( fullpath, 0400 ) < 0 ) ) {
379 return ( 0 ); // error, yeah, I know, no way to know why it failed..
387 time_t pnd_is_locked ( char *lockname ) {
388 char fullpath [ PATH_MAX ];
390 snprintf ( fullpath, PATH_MAX, "%s/%s", PND_LOCK_PATH, lockname );
393 rv = stat ( fullpath, &statbuf );
395 if ( rv == ENOENT ) {
396 return ( 0 ); // file not existk, so no lock
397 } else if ( rv < 0 ) {
398 return ( 0 ); // assume unlocked for error, so app can continue?
401 return ( statbuf.st_mtime );
404 void pnd_unlock ( char *lockname ) {
405 char fullpath [ PATH_MAX ];
406 snprintf ( fullpath, PATH_MAX, "%s/%s", PND_LOCK_PATH, lockname );
413 unsigned char pnd_wait_for_unlock ( char *lockname, unsigned short int max, unsigned int usec_delta ) {
415 // check right off the top
416 if ( ! pnd_is_locked ( lockname ) ) {
417 return ( 1 ); // all clear!
420 unsigned short int count = 0;
421 while ( count < max ) {
423 if ( ! pnd_is_locked ( lockname ) ) {
424 return ( 1 ); // all clear!
427 usleep ( usec_delta );