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