1 #define MAX_FILE_NAME 1024
2
3 #include "sowing.h"
4 #if defined(HAVE_PWD_H)
5 #include <pwd.h>
6 #endif
7 #include <ctype.h>
8 /*
9 Here's an unpleasent fact. On Intel systems, include-ipsc/sys/types.h
10 contains "typedef long time_t" and
11 include/time.h contains "typedef long int time_t". We can fix this by
12 defining __TIME_T after types.h is included.
13 */
14 #include <sys/types.h>
15 #if defined(intelnx) && !defined(intelparagon) && !defined(__TIME_T)
16 #define __TIME_T
17 #endif
18 #include <sys/stat.h>
19 /* Here's an unpleasent fact. On Intel systems, unistd contains REDEFINITIONS
20 of SEEK_SET, SEEK_CUR, and SEEK_END that are not guarded (in fact, the
21 unistd.h file contains no guards against multiple inclusion!). */
22 #if defined(intelnx) && !defined(intelparagon)
23 #undef SEEK_SET
24 #undef SEEK_CUR
25 #undef SEEK_END
26 #endif
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 /*
32 extern char *mktemp();
33 extern char *getcwd();
34 */
35
36 /* WARNING - some systems don't have stdlib.h */
37 #if !defined(NOSTDHDR)
38 #include <stdlib.h>
39
40 #if defined(tc2000)
41 extern char *getenv();
42 #endif
43
44 #else
45 extern char *getenv();
46 #endif
47
48 #if defined(__MSDOS__) || defined(WIN32)
49 typedef unsigned short u_short;
50 #endif
51 #if (defined(intelnx) && !defined(intelparagon)) || defined(__MSDOS__) || defined(WIN32)
52 typedef u_short uid_t;
53 typedef u_short gid_t;
54 #endif
55
56 /* Set to 1 to provide debugging output */
57 static int dbg = 1;
58
59 /* Prototypes for internal routines */
60 int SYiTestFile( const char *, char, uid_t, gid_t );
61
62 #if defined(HAVE_PWD_H)
63 /*@
64 SYGetFullPath - Given a filename, return the fully qualified
65 file name.
66
67 Input parameters:
68 . path - pathname to qualify
69 . fullpath - pointer to buffer to hold full pathname
70 . flen - size of fullpath
71
72 Notes:
73 The main role of this routine is to include the current working
74 directory in the full path name. It also handles the case of
75 a file that starts with '/tmp_mnt/'; in the distant past, this
76 needed to be removed before processing the file path.
77
78 In addition, it handles the common shell convention of '~<username>'
79 as the home directory of user '<username>'.
80 @*/
SYGetFullPath(const char * path,char * fullpath,int flen)81 void SYGetFullPath( const char *path, char *fullpath, int flen )
82 {
83 struct passwd *pwde;
84 int ln;
85
86 if (path[0] == '/') {
87 if (strncmp( "/tmp_mnt/", path, 9 ) == 0)
88 strncpy( fullpath, path + 8, flen );
89 else
90 strncpy( fullpath, path, flen );
91 return;
92 }
93 SYGetwd( fullpath, flen );
94 strncat( fullpath,"/",flen - strlen(fullpath) );
95 if ( path[0] == '.' && path[1] == '/' )
96 strncat( fullpath, path+2, flen - strlen(fullpath) - 1 );
97 else
98 strncat( fullpath, path, flen - strlen(fullpath) - 1 );
99
100 /* Remove the various "special" forms (~username/ and ~/) */
101 if (fullpath[0] == '~') {
102 char tmppath[MAX_FILE_NAME];
103 if (fullpath[1] == '/') {
104 pwde = getpwuid( geteuid() );
105 if (!pwde) return;
106 strcpy( tmppath, pwde->pw_dir );
107 ln = strlen( tmppath );
108 if (tmppath[ln-1] != '/') strcat( tmppath+ln-1, "/" );
109 strcat( tmppath, fullpath + 2 );
110 strncpy( fullpath, tmppath, flen );
111 }
112 else {
113 char *p, *name;
114
115 /* Find username */
116 name = fullpath + 1;
117 p = name;
118 while (*p && isalnum(*p)) p++;
119 *p = 0; p++;
120 pwde = getpwnam( name );
121 if (!pwde) return;
122
123 strcpy( tmppath, pwde->pw_dir );
124 ln = strlen( tmppath );
125 if (tmppath[ln-1] != '/') strcat( tmppath+ln-1, "/" );
126 strcat( tmppath, p );
127 strncpy( fullpath, tmppath, flen );
128 }
129 }
130 /* Remove the automounter part of the path */
131 if (strncmp( fullpath, "/tmp_mnt/", 9 ) == 0) {
132 char tmppath[MAX_FILE_NAME];
133 strcpy( tmppath, fullpath + 8 );
134 strcpy( fullpath, tmppath );
135 }
136 /* We could try to handle things like the removal of .. etc */
137 }
138 #else
SYGetFullPath(const char * path,char * fullpath,int flen)139 void SYGetFullPath( const char *path, char *fullpath, int flen )
140 {
141 strcpy( fullpath, path );
142 }
143 #endif
144
145 /*@
146 SYGetRelativePath - Given a filename, return the relative path (remove
147 all directory specifiers)
148
149 Input parameters:
150 . fullpath - full pathname
151 . path - pointer to buffer to hold relative pathname
152 . flen - size of path
153
154 Notes:
155 Simply removes everything up to the last directory separator ('/'),
156 and returns that path.
157 @*/
SYGetRelativePath(const char * fullpath,char * path,int flen)158 void SYGetRelativePath( const char *fullpath, char *path, int flen )
159 {
160 const char *p;
161
162 /* Find last '/' */
163 p = strrchr( fullpath, '/' );
164 if (!p) p = fullpath;
165 else p++;
166 strncpy( path, p, flen );
167 }
168
169 #if defined(HAVE_PWD_H)
170
171 /*@
172 SYGetUserName - Return the name of the user.
173
174 Input Parameter:
175 nlen - length of name
176 Output Parameter:
177 . name - contains user name. Must be long enough to hold the name
178
179 @*/
SYGetUserName(char * name,int nlen)180 void SYGetUserName( char *name, int nlen )
181 {
182 struct passwd *pw;
183
184 pw = getpwuid( getuid() );
185 if (!pw)
186 strncpy( name, "Unknown",nlen );
187 else
188 strncpy( name, pw->pw_name,nlen );
189 }
190 #else
SYGetUserName(char * name,int nlen)191 void SYGetUserName( char *name, int nlen )
192 {
193 strncpy( name, "Unknown", nlen );
194 }
195 #endif /* !HAVE_PWD_H */
196 #if !defined(__MSDOS__) && !defined(WIN32) && (!defined(intelnx) || defined(paragon))
197
198 #if defined(HAVE_UNAME)
199 #include <sys/utsname.h>
200 #endif
201 #if defined(HAVE_GETHOSTBYNAME)
202 #if defined(HAVE_NETDB_H)
203 /* Some Solaris systems can't compile netdb.h */
204 #include <netdb.h>
205 #else
206 #undef HAVE_GETHOSTBYNAME
207 #endif
208 #endif /* HAVE_GETHOSTBYNAME */
209 #if defined(HAVE_SYSINFO)
210 #if defined(HAVE_SYS_SYSTEMINFO_H)
211 #include <sys/systeminfo.h>
212 #else
213 #ifdef HAVE_SYSINFO
214 #undef HAVE_SYSINFO
215 #endif
216 #endif
217 #endif
218
219
220 /*@
221 SYGetHostName - Return the name of the host.
222
223 Input Parameter:
224 nlen - length of name
225 Output Parameter:
226 . name - contains host name. Must be long enough to hold the name
227 This is the fully qualified name, including the domain.
228 @*/
SYGetHostName(char * name,int nlen)229 void SYGetHostName( char *name, int nlen )
230 {
231 /* This is the perfered form, IF IT WORKS. */
232 #if defined(HAVE_UNAME) && defined(HAVE_GETHOSTBYNAME)
233 struct utsname utname;
234 struct hostent *he;
235 uname( &utname );
236 he = gethostbyname( utname.nodename );
237 /* We must NOT use strncpy because it will null pad to the full length
238 (nlen). If the user has not allocated MPI_MAX_PROCESSOR_NAME chars,
239 then this will unnecessarily overwrite storage.
240 */
241 /* strncpy(name,he->h_name,nlen); */
242 {
243 char *p_out = name;
244 char *p_in = he->h_name;
245 int i;
246 for (i=0; i<nlen-1 && *p_in; i++)
247 *p_out++ = *p_in++;
248 *p_out = 0;
249 }
250 #else
251 #if defined(HAVE_UNAME)
252 struct utsname utname;
253 uname(&utname);
254 /* We must NOT use strncpy because it will null pad to the full length
255 (nlen). If the user has not allocated MPI_MAX_PROCESSOR_NAME chars,
256 then this will unnecessarily overwrite storage.
257 */
258 /* strncpy(name,utname.nodename,nlen); */
259 {
260 char *p_out = name;
261 char *p_in = utname.nodename;
262 int i;
263 for (i=0; i<nlen-1 && *p_in; i++)
264 *p_out++ = *p_in++;
265 *p_out = 0;
266 }
267 #elif defined(HAVE_GETHOSTNAME)
268 gethostname( name, nlen );
269 #elif defined(HAVE_SYSINFO)
270 sysinfo(SI_HOSTNAME, name, nlen);
271 #else
272 strncpy( name, "Unknown!", nlen );
273 #endif
274 /* See if this name includes the domain */
275 if (!strchr(name,'.')) {
276 int l;
277 l = strlen(name);
278 name[l++] = '.';
279 name[l] = 0; /* In case we have neither SYSINFO or GETDOMAINNAME */
280 #if defined(HAVE_SYSINFO) && defined(SI_SRPC_DOMAIN)
281 sysinfo( SI_SRPC_DOMAIN,name+l,nlen-l);
282 #elif defined(HAVE_GETDOMAINNAME)
283 getdomainname( name+l, nlen - l );
284 #endif
285 }
286 #endif
287 #ifdef FOO
288 #if defined(solaris)
289 struct utsname utname;
290 uname(&utname);
291 strncpy(name,utname.nodename,nlen);
292 #else
293 /* sysinfo(SI_HOSTNAME, name, nlen); */
294 gethostname(name, nlen);
295 #endif
296 /* See if this name includes the domain */
297 if (!strchr(name,'.')) {
298 int l;
299 l = strlen(name);
300 name[l++] = '.';
301 #if defined(solaris)
302 sysinfo( SI_SRPC_DOMAIN,name+l,nlen-l);
303 #else
304 getdomainname( name+l, nlen - l );
305 #endif
306 }
307 #endif
308 }
309 #else
SYGetHostName(char * name,nlen)310 void SYGetHostName( char *name, nlen )
311 {
312 #if defined(intelnx)
313 #if defined(inteldelta)
314 strncpy( name, "IntelDelta", nlen );
315 #else
316 strncpy( name, "IntelNX", nlen );
317 #endif
318 #else
319 strncpy( name, "Unknown", nlen );
320 #endif
321 }
322 #endif
323
324 #if !defined(__MSDOS__) && !defined(WIN32)
325 int SYiTestFile( const char *, char, uid_t, gid_t );
326
327 /*+
328 SYiTestFile - Test for a file existing with a specified mode.
329
330 Input Parameters:
331 . fname - name of file
332 . mode - mode. One of 'r', 'w', 'e'
333 . uid,gid - user and group id to use
334
335 Returns:
336 1 if file exists with given mode, 0 otherwise.
337 +*/
SYiTestFile(const char * fname,char mode,uid_t uid,gid_t gid)338 int SYiTestFile( const char *fname, char mode, uid_t uid, gid_t gid )
339 {
340 int err;
341 struct stat statbuf;
342 int stmode, rbit, wbit, ebit;
343
344 if (!fname) return 0;
345
346 /* Check to see if fname is a valid regular FILE */
347 err = stat( fname, &statbuf );
348 if (err != 0) return 0;
349
350 /* At least the file exists ... */
351 stmode = statbuf.st_mode;
352 #if defined(rs6000) || defined(HPUX)
353 #define S_IFREG _S_IFREG
354 #endif
355 /* if (!S_ISREG(stmode)) return 0; */
356 #if defined(intelparagon)
357 if (!S_ISREG(stmode)) return 0;
358 #else
359 if (!(S_IFREG & stmode)) return 0;
360 #endif
361 /* Test for accessible. */
362 if (statbuf.st_uid == uid) {
363 rbit = S_IRUSR;
364 wbit = S_IWUSR;
365 ebit = S_IXUSR;
366 }
367 else if (statbuf.st_gid == gid) {
368 rbit = S_IRGRP;
369 wbit = S_IWGRP;
370 ebit = S_IXGRP;
371 }
372 else {
373 rbit = S_IROTH;
374 wbit = S_IWOTH;
375 ebit = S_IXOTH;
376 }
377 if (mode == 'r') {
378 if ((stmode & rbit)) return 1;
379 }
380 else if (mode == 'w') {
381 if ((stmode & wbit)) return 1;
382 }
383 else if (mode == 'e') {
384 if ((stmode & ebit)) return 1;
385 }
386 return 0;
387 }
SYiFileExists(const char * fname,char mode)388 int SYiFileExists( const char *fname, char mode )
389 {
390 static int set_ids = 0;
391 static uid_t uid;
392 static gid_t gid;
393 int err;
394 struct stat statbuf;
395 int stmode, rbit, wbit, ebit;
396
397 if (!fname) return 0;
398
399 if (!set_ids) {
400 uid = getuid();
401 gid = getgid();
402 set_ids = 1;
403 }
404
405 /* Check to see if the environment variable is a valid regular FILE */
406 err = stat( fname, &statbuf );
407 if (err != 0) return 0;
408
409 /* At least the file exists ... */
410 stmode = statbuf.st_mode;
411 #if defined(rs6000) || defined(HPUX)
412 #define S_IFREG _S_IFREG
413 #endif
414 /* if (!S_ISREG(stmode)) return 0; */
415 #if defined(intelparagon)
416 if (!S_ISREG(stmode)) return 0;
417 #else
418 if (!(S_IFREG & stmode)) return 0;
419 #endif
420 /* Test for accessible. */
421 if (statbuf.st_uid == uid) {
422 rbit = S_IRUSR;
423 wbit = S_IWUSR;
424 ebit = S_IXUSR;
425 }
426 else if (statbuf.st_gid == gid) {
427 rbit = S_IRGRP;
428 wbit = S_IWGRP;
429 ebit = S_IXGRP;
430 }
431 else {
432 rbit = S_IROTH;
433 wbit = S_IWOTH;
434 ebit = S_IXOTH;
435 }
436 if (mode == 'r') {
437 if ((stmode & rbit)) return 1;
438 }
439 else if (mode == 'w') {
440 if ((stmode & wbit)) return 1;
441 }
442 else if (mode == 'e') {
443 if ((stmode & ebit)) return 1;
444 }
445 return 0;
446 }
447 #else
SYiTestFile(const char * fname,char mode,uid_t uid,gid_t gid)448 int SYiTestFile( const char *fname, char mode, uid_t uid, gid_t gid )
449 {
450 int err;
451 struct stat statbuf;
452 int stmode, rbit, wbit, ebit;
453
454 if (!fname) return 0;
455
456 /* Check to see if the environment variable is a valid regular FILE */
457 err = stat( fname, &statbuf );
458 if (err != 0) return 0;
459
460 /* At least the file exists ... */
461 stmode = statbuf.st_mode;
462 if (!(S_IFREG & stmode)) return 0;
463 /* Test for accessible. */
464 rbit = S_IREAD;
465 wbit = S_IWRITE;
466 ebit = S_IEXEC;
467 if (mode == 'r') {
468 if ((stmode & rbit)) return 1;
469 }
470 else if (mode == 'w') {
471 if ((stmode & wbit)) return 1;
472 }
473 else if (mode == 'e') {
474 if ((stmode & ebit)) return 1;
475 }
476 return 0;
477 }
478 #endif /* MSDOS */
479
480 #ifndef __MSDOS__
481 /*@
482 SYGetFileFromPath - Find a file from a name and an path string
483 A default may be provided.
484
485 Input Parameters:
486 + path - A string containing "directory:directory:..." (without the
487 quotes, of course).
488 As a special case, if the name is a single FILE, that file is
489 used.
490 . defname - default name
491 . name - file name to use with the directories from path
492 - mode - file mode desired (usually 'r' for readable; 'w' for writable and
493 'e' for executable are also supported)
494
495 Output Parameter:
496 . fname - qualified file name
497
498 Notes:
499 Searches through path for a file with the access mode desired. The
500 file name is made up of a directory from the path and the 'name'.
501 If no match is found, 'fname' is retured with the value 'defname'.
502 In that case, if 'defname' does not exist with the correct mode,
503 the return value is '0' (failure). 'fname' is `always` set.
504
505 Returns:
506 1 on success, 0 on failure.
507 @*/
SYGetFileFromPath(const char * path,const char * defname,const char * name,char * fname,char mode)508 int SYGetFileFromPath( const char *path, const char *defname,
509 const char *name, char *fname, char mode )
510 {
511 char *p, *cdir;
512 int ln;
513 uid_t uid;
514 gid_t gid;
515 char trial[MAX_FILE_NAME];
516 char *senv, *env;
517
518 /* Setup default */
519 SYGetFullPath(defname,fname,MAX_FILE_NAME);
520
521 /* Get the (effective) user and group of the caller */
522 uid = geteuid();
523 gid = getegid();
524
525 if (path) {
526
527 /* Check to see if the path is a valid regular FILE */
528 if (dbg)
529 fprintf(stderr,"Testing path as file %s\n", path);
530 if (SYiTestFile( path, mode, uid, gid )) {
531 strcpy( fname, path );
532 return 1;
533 }
534
535 /* Make a local copy of path and mangle it */
536 senv = env = (char *)MALLOC( strlen(path) + 1 );
537 if (!senv) { fprintf( stderr, "Error allocating memory\n" ); return 0; }
538 strcpy( env, path );
539 while (env) {
540 /* Find next directory in env */
541 cdir = env;
542 p = strchr( env, ':' );
543 if (p) {
544 *p = 0;
545 env = p + 1;
546 }
547 else
548 env = 0;
549
550 /* Form trial file name */
551 strcpy( trial, cdir );
552 ln = strlen( trial );
553 if (trial[ln-1] != '/')
554 trial[ln++] = '/';
555
556 strcpy( trial + ln, name );
557
558 if (dbg)
559 fprintf(stderr,"Testing file %s\n", trial);
560 if (SYiTestFile( trial, mode, uid, gid )) {
561 /* need SYGetFullPath rather then copy in case path has . in it */
562 SYGetFullPath( trial, fname, MAX_FILE_NAME );
563 FREE( senv );
564 return 1;
565 }
566 }
567
568 FREE( senv );
569 } /* end of if path */
570
571 if (dbg)
572 fprintf(stderr,"Testing file %s\n", fname);
573 if (SYiTestFile( fname, mode, uid, gid )) return 1;
574 else return 0;
575 }
576 #else
577 /* MSDOS version does not use uid, gid */
SYGetFileFromPath(const char * path,const char * defname,const char * name,char * fname,char mode)578 int SYGetFileFromPath( const char *path, const char *defname, const char *name,
579 char *fname, char mode )
580 {
581 char *p, *cdir;
582 int ln;
583 char trial[MAX_FILE_NAME];
584 char *senv, *env;
585 uid_t uid;
586 gid_t gid;
587
588 /* Setup default */
589 SYGetFullPath(defname,fname,MAX_FILE_NAME);
590
591 if (path) {
592
593 /* Check to see if the path is a valid regular FILE */
594 if (SYiTestFile( path, mode, uid, gid )) {
595 strcpy( fname, path );
596 return 1;
597 }
598
599 /* Make a local copy of path and mangle it */
600 senv = env = (char *)MALLOC( strlen(path) + 1 );
601 if (!senv) { fprintf( stderr, "Error allocating memory\n" ); return 0; }
602 strcpy( env, path );
603 while (env) {
604 /* Find next directory in env */
605 cdir = env;
606 p = strchr( env, ':' );
607 if (p) {
608 *p = 0;
609 env = p + 1;
610 }
611 else
612 env = 0;
613
614 /* Form trial file name */
615 strcpy( trial, cdir );
616 ln = strlen( trial );
617 if (trial[ln-1] != '/')
618 trial[ln++] = '/';
619
620 strcpy( trial + ln, name );
621
622 if (SYiTestFile( trial, mode, uid, gid )) {
623 /* need SYGetFullPath rather then copy in case path has .
624 in it */
625 SYGetFullPath( trial, fname, MAX_FILE_NAME );
626 FREE( senv );
627 return 1;
628 }
629 }
630
631 FREE( senv );
632 } /* end of if path */
633
634 if (SYiTestFile( fname, mode, uid, gid )) return 1;
635 else return 0;
636 }
637 #endif /* __MSDOS__ */
638
639 /*@
640 SYGetFileFromEnvironment - Find a file from a name and an environment
641 variable. A default may be provided.
642
643 Input Parameters:
644 . env - name of environment variable. The contents of this variable
645 should be of the form "directory:directory:..." (without the
646 quotes, of course).
647 As a special case, if the name is a single FILE, that file is
648 used.
649
650 . defname - default name
651 . name - file name to use with the directories from env
652 . mode - file mode desired (usually 'r' for readable; 'w' for writable and
653 'e' for executable are also supported)
654
655 Output Parameter:
656 . fname - qualified file name
657
658 Notes:
659 This is like 'SYGetFileFromPath', except the environement variable
660 provides the path.
661
662 Returns:
663 1 on success, 0 on failure.
664 @*/
SYGetFileFromEnvironment(const char * env,const char * defname,const char * name,char * fname,char mode)665 int SYGetFileFromEnvironment( const char *env, const char *defname,
666 const char *name, char *fname, char mode )
667 {
668 char *edir;
669
670 /* Get the environment values */
671 edir = getenv( env );
672
673 return SYGetFileFromPath( edir, defname, name, fname, mode );
674 }
675
676 /*@
677 SYOpenWritableFile - Open a writeable file, given a directory path and
678 a filename.
679
680 Input Parameters:
681 . dirpath - The list of directories. The contents of this variable
682 should be of the form "directory:directory:..." (without the
683 quotes, of course).
684 . defname - default name (unused for now)
685 . name - file name to use with the directories from env
686 . istmp - if 1, use mktemp to generate a file name. "name" must be in the
687 correct form for mktemp (six trailing X's).
688
689 Output Parameter:
690 . fname - qualified file name
691
692 Returns:
693 Pointer to open FILE.
694 @*/
SYOpenWritableFile(const char * dirpath,const char * defname,const char * name,char * fname,int istmp)695 FILE *SYOpenWritableFile( const char *dirpath, const char *defname,
696 const char *name, char *fname, int istmp )
697 {
698 const char *cdir, *p;
699 int ln;
700 FILE *fp;
701
702 while (dirpath && *dirpath) {
703 /* Find next directory in env */
704 cdir = dirpath;
705 p = strchr( dirpath, ':' );
706 if (p) {
707 dirpath = p + 1;
708 }
709 else {
710 p = dirpath + strlen(dirpath);
711 dirpath = 0;
712 }
713
714 /* Form trial file name */
715 strncpy( fname, cdir, (int)(p-cdir) );
716 fname[(int)(p-cdir)] = 0;
717 ln = strlen( fname );
718 if (fname[ln-1] != '/')
719 fname[ln++] = '/';
720
721 strcpy( fname + ln, name );
722 if (istmp)
723 fname = mktemp( fname );
724
725 /* Form full path name */
726 /* strcpy( path, fname ); */
727 /* SYGetFullPath( path, fname, MAX_FILE_LEN ); */
728
729 /* Is the file accessible? */
730 /* fprintf( stderr, "Trying filename %s\n", fname ); */
731 fp = fopen( fname, "w" );
732 if (fp) return fp;
733 }
734
735 /* Try the default name */
736 if (istmp)
737 fname = mktemp( fname );
738 fp = fopen( fname, "w" );
739
740 return fp;
741 }
742
743 /*@
744 SYGetwd - Get the current working directory
745
746 Input paramters:
747 . path - use to hold the result value
748 . len - maximum length of path
749 @*/
SYGetwd(char * path,int len)750 void SYGetwd( char *path, int len )
751 {
752 #if defined(tc2000) || (defined(sun4) && !defined(solaris))
753 getwd( path );
754 #elif defined(__MSDOS__) || defined(WIN32)
755 /* path[0] = 'A' + (_getdrive() - 1);
756 path[1] = ':';
757 _getcwd( path + 2, len - 2 );
758 */
759 #if defined(__TURBOC__)
760 getcwd( path, len );
761 #else
762 _getcwd( path, len );
763 #endif
764 #else
765 getcwd( path, len );
766 #endif
767 }
768
769 #if !defined(__MSDOS__) && !defined(WIN32)
770 #include <sys/param.h>
771 #endif
772 #ifndef MAXPATHLEN
773 /* sys/param.h in intelnx does not include MAXPATHLEN! */
774 #define MAXPATHLEN 1024
775 #endif
776
777 /*@
778 SYGetRealpath - get the path without symbolic links etc and in absolute
779 form.
780
781 Input Parameter:
782 . path - path to resolve
783
784 Output Parameter:
785 . rpath - resolved path
786
787 Note: rpath is assumed to be of length MAXPATHLEN
788
789 Note: Systems that use the automounter often generate absolute paths
790 of the form "/tmp_mnt....". However, the automounter will fail to
791 mount this path if it isn't already mounted, so we remove this from
792 the head of the line. This may cause problems if, for some reason,
793 /tmp_mnt is valid and not the result of the automounter.
794 @*/
SYGetRealpath(const char * path,char * rpath)795 char *SYGetRealpath( const char *path, char *rpath )
796 {
797 #if defined(sun4)
798 extern char *realpath();
799 realpath( path, rpath );
800
801 #elif defined(intelnx) || defined(__MSDOS__) || defined(WIN32)
802 strcpy( rpath, path );
803
804 #else
805 #if defined(IRIX)
806 extern char *strchr();
807 #endif
808 #ifdef FOO
809 int n, m, N;
810 char tmp1[MAXPATHLEN], tmp3[MAXPATHLEN], tmp4[MAXPATHLEN], *tmp2;
811 #endif
812 /* Algorithm: we move through the path, replacing links with the
813 real paths.
814 */
815 strcpy( rpath, path );
816 #ifdef FOO
817 /* THIS IS BROKEN. IT CAUSES INFINITE LOOPS ON IRIX, BECAUSE
818 THE CODE ON FAILURE FROM READLINK WILL NEVER SET N TO ZERO */
819 N = strlen(rpath);
820 while (N) {
821 strncpy(tmp1,rpath,N); tmp1[N] = 0;
822 n = readlink(tmp1,tmp3,MAXPATHLEN);
823 if (n > 0) {
824 tmp3[n] = 0; /* readlink does not automatically add 0 to string end */
825 if (tmp3[0] != '/') {
826 tmp2 = strchr(tmp1,'/');
827 m = strlen(tmp1) - strlen(tmp2);
828 strncpy(tmp4,tmp1,m); tmp4[m] = 0;
829 strncat(tmp4,"/",MAXPATHLEN - strlen(tmp4));
830 strncat(tmp4,tmp3,MAXPATHLEN - strlen(tmp4));
831 SYGetRealpath(tmp4,rpath);
832 strncat(rpath,path+N,MAXPATHLEN - strlen(rpath));
833 return rpath;
834 }
835 else {
836 SYGetRealpath(tmp3,tmp1);
837 strncpy(rpath,tmp1,MAXPATHLEN);
838 strncat(rpath,path+N,MAXPATHLEN - strlen(rpath));
839 return rpath;
840 }
841 }
842 tmp2 = strchr(tmp1,'/');
843 if (tmp2) N = strlen(tmp1) - strlen(tmp2);
844 else N = strlen(tmp1);
845 }
846 strncpy(rpath,path,MAXPATHLEN);
847 #endif
848 #endif
849 if (strncmp( "/tmp_mnt/", rpath, 9 ) == 0) {
850 char tmp3[MAXPATHLEN];
851 strcpy( tmp3, rpath + 8 );
852 strcpy( rpath, tmp3 );
853 }
854 return rpath;
855 }
856
857 #if !defined(__MSDOS__) && !defined(WIN32)
858 /*@
859 SYRemoveHomeDir - Given a complete true path, remove user's home directory
860
861 Input Parameter:
862 . path - path to be possibly modified
863
864 Note:
865 Given a complete path (for instance by SYGetRealpath), if the path begins
866 with the users home directory, the user's home directory is removed.
867
868 This is useful on systems where a users home directory may have
869 different names on different machines, or different names each time
870 one logs in (such systems exist!).
871 @*/
SYRemoveHomeDir(char * path)872 void SYRemoveHomeDir( char *path )
873 {
874 struct passwd *pw = 0;
875 char tmp1[MAXPATHLEN], tmp2[MAXPATHLEN], *d1, *d2;
876 int len;
877
878 pw = getpwuid( getuid() );
879 if (!pw) return;
880 strcpy(tmp1, pw->pw_dir);
881 SYGetRealpath( tmp1, tmp2 );
882
883 /* some have /tmp_mnt; others don't */
884 if (!strncmp(path,"/tmp_mnt",8)) d1 = path + 8; else d1 = path;
885 if (!strncmp(tmp2,"/tmp_mnt",8)) d2 = tmp2 + 8; else d2 = tmp2;
886 if (strncmp(d1,d2,strlen(d2))) return;
887 len = strlen(d2) + 1;
888 strcpy(tmp1,d1+len); /* we know these will fit */
889 strcpy(path,tmp1);
890 }
891 #else
SYRemoveHomeDir(char * path)892 void SYRemoveHomeDir( char *path )
893 {
894 }
895 #endif /* MSDOS */
896
897 #ifndef MAXHOSTNAMELEN
898 #define MAXHOSTNAMELEN 64
899 #endif
900 /*@
901 SYIsMachineHost - returns true if name passed in matches host
902 name else false.
903
904 Input Paramters:
905 . machinename - Name of the machine to test
906
907 @*/
SYIsMachineHost(const char * machinename)908 int SYIsMachineHost( const char *machinename )
909 {
910 static char localhost[MAXHOSTNAMELEN];
911 static int hostlength = 0;
912 int namelen;
913 char *tmp;
914
915 if (!hostlength) {
916 SYGetHostName(localhost,MAXHOSTNAMELEN);
917 hostlength = strlen(localhost);
918 #if !defined(RELIABLEHOSTNAME)
919 if ((tmp = strchr(localhost,'.'))) {
920 hostlength = strlen(localhost) - strlen(tmp);
921 }
922 #endif
923 }
924 #if !defined(RELIABLEHOSTNAME)
925 /* Only test leading characters of the localname against the leading
926 characters of the host */
927 if ((tmp = strchr( machinename, '.' )))
928 namelen = strlen( machinename ) - strlen( tmp );
929 else
930 namelen = strlen( machinename );
931 return (namelen == hostlength && !strncmp(machinename,localhost,hostlength));
932 #else
933 return !strncmp(machinename,localhost,hostlength);
934 #endif
935 }
936
937 #ifndef S_ISDIR
938 #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
939 #endif
940 /*@
941 SYIsDirectory - Tests to see if a filename is a directory.
942
943 Input Parameters:
944 . fname - name of file
945
946 Returns:
947 1 if file is a directory, 0 otherwise
948 @*/
SYIsDirectory(const char * fname)949 int SYIsDirectory( const char *fname )
950 {
951 int err;
952 struct stat statbuf;
953 int stmode;
954
955 if (!fname) return 0;
956
957 err = stat( fname, &statbuf );
958 if (err != 0) return 0;
959
960 /* At least the file exists ... */
961 stmode = statbuf.st_mode;
962 return S_ISDIR(stmode);
963 }
964 #ifndef __MSDOS__
965
966 #include <fcntl.h>
967
968 /*@
969 SYMakeAllDirs - Make all of the directories in the file name
970
971 Input Parameter:
972 . name - name of file. The last element is a file NAME, not a directory
973
974 Notes:
975 This routine attempts to create the intervening directories if they
976 do not exist.
977 @*/
SYMakeAllDirs(const char * name,int fmode)978 void SYMakeAllDirs( const char *name, int fmode )
979 {
980 char *p, *pn;
981 char dirname[1024];
982 int err;
983 struct stat statbuf;
984
985 strcpy( dirname, name );
986 p = dirname;
987 /* Make sure that fmode has x bits set */
988 if (! (fmode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
989 fmode |= (S_IXUSR | S_IXGRP | S_IXOTH);
990 }
991 while (*p) {
992 /* find the next component */
993 pn = p + 1;
994 while (*pn && *pn != '/') pn++;
995 if (*pn != '/') break;
996 *pn = 0;
997 err = stat( dirname, &statbuf );
998 if (err != 0) {
999 err = mkdir( dirname, fmode );
1000 if (err < 0) {
1001 fprintf( stderr, "Failed to make directory %s", dirname );
1002 return;
1003 }
1004 }
1005 *pn = '/';
1006 p = pn + 1;
1007 }
1008 }
1009
1010 #include <time.h> /*I <time.h> I*/
1011 /* Get the date that a file was last changed */
1012 /*@
1013 SYLastChangeToFile - Gets the date that a file was changed as a string or
1014 timeval structure
1015
1016 Input Parameter:
1017 . fname - name of file
1018
1019 Output Parameters:
1020 . date - string to hold date (may be null)
1021 . ltm - tm structure for time (may be null)
1022 @*/
SYLastChangeToFile(const char * fname,char * date,struct tm * ltm)1023 void SYLastChangeToFile( const char *fname, char *date, struct tm *ltm )
1024 {
1025 struct stat buf;
1026 struct tm *tim;
1027
1028 if (stat( fname, &buf ) == 0) {
1029 tim = localtime( &(buf.st_mtime) );
1030 if (ltm) *ltm = *tim;
1031 if (date)
1032 sprintf( date, "%d/%d/%d",
1033 tim->tm_mon+1, tim->tm_mday, tim->tm_year+1900 );
1034 }
1035 else {
1036 /* Could not stat file */
1037 if (date)
1038 date[0] = '\0';
1039 if (ltm) {
1040 ltm->tm_mon = ltm->tm_mday = ltm->tm_year = 0;
1041 }
1042 }
1043 }
1044
1045 /* Return 1 if newfile is newer than oldfile */
1046 /* Return 0 if newfile does not exist, and 1 if oldfile does not exist */
SYFileNewer(char * newfile,char * oldfile)1047 int SYFileNewer( char *newfile, char *oldfile )
1048 {
1049 struct stat new_st, old_st;
1050
1051 if (stat( newfile, &new_st )) return 0;
1052 if (stat( oldfile, &old_st )) return 1;
1053
1054 return (new_st.st_mtime > old_st.st_mtime);
1055 }
1056
1057 /*
1058 These routines may be used to get exclusive access to a file; they
1059 replace fopen and fclose.
1060
1061 We have to fcntl to insure that NFS-mounted files are locked.
1062 */
1063
1064 /* Experimentation on the SP-1 at ANL shows that fcntl does not work under
1065 AIX */
1066 #if !defined(rs6000) && !defined(intelnx)
1067 #define FCNTL_WORKS
1068 #include <fcntl.h>
1069 #endif
1070
1071 #ifndef FCNTL_WORKS
1072 static char *lockfile = 0;
1073 static int lockfilefd = -1;
1074 #endif
1075
SYfopenLock(char * name,char * type)1076 FILE *SYfopenLock( char *name, char *type )
1077 {
1078 FILE *fp;
1079 int fd;
1080 int cnt;
1081 #ifdef FCNTL_WORKS
1082 struct flock FL;
1083 #endif
1084
1085 fp = fopen( name, type );
1086 if (!fp) return 0;
1087
1088 #ifdef FCNTL_WORKS
1089 fd = fileno(fp);
1090
1091 FL.l_type = F_WRLCK;
1092 FL.l_whence = SEEK_SET;
1093 FL.l_start = 0;
1094 FL.l_len = 0;
1095 /*
1096 fprintf( stdout, "About to lock file %s\n", name ); fflush( stdout );
1097 */
1098 /*
1099 This code attempts to avoid deadlock by not using blocking lock
1100 requests. However, it requires correct behavior by the operating
1101 system. AIX 3.2.4, as a counter-example, seems to block on these
1102 non-blocking lock requests (on the remote nodes). Sigh...
1103 */
1104 if (fcntl( fd, F_SETLK, &FL ) == -1) {
1105 /*
1106 fprintf( stdout, "Could not lock file %s; trying again...\n", name );
1107 fflush( stdout );
1108 */
1109 cnt = 10;
1110 while (cnt--) {
1111 sleep(5);
1112 if (fcntl( fd, F_SETLK, &FL ) != -1) break;
1113 }
1114 if (!cnt) {
1115 fprintf( stdout, "Could not lock file %s\n", name );
1116 fclose( fp );
1117 return 0;
1118 }
1119 }
1120 /*
1121 fprintf( stdout, "Locked file %s\n", name );
1122 fflush( stdout );
1123 */
1124 #else
1125 /* We use a file-based locking mechanism here. Only one file may be locked
1126 with this system */
1127 if (lockfile) {
1128 fclose( fp );
1129 return 0;
1130 }
1131 lockfile = (char *)MALLOC( strlen(name) + 6 ); CHKPTRN(lockfile);
1132 strcpy( lockfile, name );
1133 strcat( lockfile, ".lock" );
1134 cnt = 10;
1135 while (cnt--) {
1136 lockfilefd = open( lockfile, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644 );
1137 if (lockfilefd >= 0) break;
1138 sleep( 5 );
1139 }
1140 if (!cnt) {
1141 fprintf( stdout, "Could not lock file %s\n", name );
1142 fclose( fp );
1143 return 0;
1144 }
1145 #endif
1146 return fp;
1147 }
SYfcloseLock(FILE * fp)1148 void SYfcloseLock( FILE *fp )
1149 {
1150 int fd;
1151 #ifdef FCNTL_WORKS
1152 struct flock FL;
1153 #endif
1154
1155 if (!fp) return;
1156 #ifdef FCNTL_WORKS
1157 fd = fileno(fp);
1158
1159 FL.l_type = F_UNLCK;
1160 FL.l_whence = SEEK_SET;
1161 FL.l_start = 0;
1162 FL.l_len = 0;
1163 fflush( fp );
1164 /* fprintf( stdout, "About to unlock file\n" ); fflush( stdout ); */
1165 /* I should not have to wait since I have the lock */
1166 fcntl( fd, F_SETLK, &FL );
1167 fclose( fp );
1168 #else
1169 /* We use a file-based locking mechanism here */
1170 fclose( fp );
1171 close( lockfilefd );
1172 lockfilefd = -1;
1173 unlink( lockfile );
1174 FREE( lockfile );
1175 lockfile = 0;
1176 #endif
1177 }
1178
1179 #else
1180 #include <time.h>
1181 /* MSDOS code for makedirs and last change should go here */
1182
1183 /* This version of MakeAllDirs knows about '\' instead of '/'.
1184 It also doesn't bother with fmode for now */
SYMakeAllDirs(const char * name,int fmode)1185 void SYMakeAllDirs( const char *name, int fmode )
1186 {
1187 char *p, *pn;
1188 char dirname[1024];
1189 int err;
1190 struct stat statbuf;
1191
1192 strcpy( dirname, name );
1193 p = dirname;
1194 while (*p) {
1195 /* find the next component */
1196 pn = p + 1;
1197 while (*pn && *pn != '/' && *pn != '\\') pn++;
1198 if (*pn != '/' && *pn != '\\') break;
1199 *pn = 0;
1200 err = stat( dirname, &statbuf );
1201 if (err != 0) {
1202 err = mkdir( dirname, fmode );
1203 if (err < 0) {
1204 fprintf( stderr, "Failed to make directory %s\n", dirname );
1205 return;
1206 }
1207 }
1208 *pn = '\\';
1209 p = pn + 1;
1210 }
1211 }
SYLastChangeToFile(const char * fname,char * date,struct tm * ltm)1212 void SYLastChangeToFile( const char *fname, char *date, struct tm *ltm )
1213 {
1214 struct stat buf;
1215 struct tm *tim;
1216
1217 if (stat( fname, &buf ) == 0) {
1218 tim = localtime( &(buf.st_mtime) );
1219 if (ltm) *ltm = *tim;
1220 if (date)
1221 sprintf( date, "%d/%d/%d",
1222 tim->tm_mon+1, tim->tm_mday, tim->tm_year+1900 );
1223 }
1224 else {
1225 /* Could not stat file */
1226 if (date)
1227 date[0] = '\0';
1228 if (ltm) {
1229 ltm->tm_mon = ltm->tm_mday = ltm->tm_year = 0;
1230 }
1231 }
1232 }
1233 #endif
1234
1235 /* Return 1 if the file exists. If fname does not exist, try fname
1236 with each of the extensions (colon separated) in extensions.
1237 The extensions do not include the "." */
SYFindFileWithExtension(char * fname,const char * extensions)1238 int SYFindFileWithExtension( char *fname, const char *extensions )
1239 {
1240 char *extLoc;
1241 const char *p;
1242
1243 if (SYiFileExists( fname, 'r' ) == 1) {
1244 return 1;
1245 }
1246 extLoc = fname + strlen(fname);
1247 *extLoc++ = '.';
1248 p = extensions;
1249 while (*p) {
1250 int i=0;
1251 while (*p && *p != ':') {
1252 extLoc[i++] = *p++;
1253 }
1254 if (*p == ':') p++;
1255 extLoc[i] = 0;
1256 /* printf( "Checking for file %s\n", fname ); */
1257 if (SYiFileExists( fname, 'r' ) == 1) {
1258 return 1;
1259 }
1260 }
1261 return 0;
1262 }
1263
1264 /*@ SYGetFileFromPathEnv - Get a full filename from a path
1265
1266 Input Parameters:
1267 + path - A string containing "directory:directory:..." (without the
1268 quotes, of course).
1269 As a special case, if the name is a single FILE, that file is
1270 used.
1271 . envname - Name of environment variable that also provides a path. See
1272 notes.
1273 . defname - Default name (returned if 'name' not found in the 'path' or
1274 path given by 'envname'.
1275 . name - File name to use with the directories from path
1276 - mode - File mode desired (usually 'r' for readable; 'w' for writable and
1277 'e' for executable are also supported)
1278
1279 Output Parameter:
1280 . fname - qualified file name
1281
1282 Returns:
1283 1 on success, 0 on failure.
1284
1285 Notes:
1286 This routine accepts both a 'path' as a set of ':' separated directories
1287 and a path as the value of an environment variable. The rule for finding
1288 the file is: First, see if the name starts with '/'. If so, the
1289 file name is absolute, and no path values ar used. Return that file,
1290 and set the return value to '0' if that file exists with the correct mode,
1291 and '1' otherwise.
1292
1293 Second, if the environment variable has a non-null value, use that
1294 as the path. If the file exists with one of those path elements,
1295 return that full path and set the return value to '0'. Third, try the
1296 specified path; if the file is found with the correct mode, return that
1297 full path and set the return value to '0'.
1298
1299 Finally, use the 'defname' as the returned path. Return '0' if that
1300 file exists with the correct mode and '1' otherwise.
1301
1302 This routine is intended to simplify locating configuration and
1303 other data files, where the package provides a default search path
1304 (usually given by the installation data directory) but permits the
1305 user to specify an alternate path with an environment variable to
1306 be searched first.
1307
1308
1309 @*/
SYGetFileFromPathEnv(const char * path,const char * envname,const char * defname,const char * name,char * fname,char mode)1310 int SYGetFileFromPathEnv( const char *path, const char *envname,
1311 const char *defname, const char *name,
1312 char *fname, char mode )
1313 {
1314 /* Allow null for the default name - in that case, use name */
1315 if (defname == 0) defname = name;
1316
1317 /* Check for absolute name */
1318 if (name[0] == '/') {
1319 if (SYiFileExists(name, mode)) {
1320 strcpy(fname, name);
1321 return 1;
1322 }
1323 }
1324
1325 /* Check for path provided by environment variable */
1326 if (envname && envname[0]) {
1327 const char *s = (const char *)getenv(envname);
1328 if (s && s[0]) {
1329 if (SYGetFileFromPath(s, defname, name, fname, mode) == 1) {
1330 return 1;
1331 }
1332 }
1333 }
1334
1335 /* Check for file in path */
1336 if (SYGetFileFromPath(path, defname, name, fname, mode) == 1) {
1337 return 1;
1338 }
1339 /* Failed to find file */
1340 return 0;
1341 }
1342