1/* efopen.c
2   Open a stdio file with appropriate permissions.  */
3
4#include "uucp.h"
5
6#include "uudefs.h"
7#include "sysdep.h"
8#include "system.h"
9
10#include <errno.h>
11
12#if HAVE_FCNTL_H
13#include <fcntl.h>
14#else
15#if HAVE_SYS_FILE_H
16#include <sys/file.h>
17#endif
18#endif
19
20#include <sys/types.h>
21#include <sys/stat.h>
22
23#ifndef O_RDONLY
24#define O_RDONLY 0
25#define O_WRONLY 1
26#define O_RDWR 2
27#endif
28
29#ifndef O_APPEND
30#ifdef FAPPEND
31#define O_APPEND FAPPEND
32#endif
33#endif
34
35#ifndef O_NOCTTY
36#define O_NOCTTY 0
37#endif
38
39#ifndef FD_CLOEXEC
40#define FD_CLOEXEC 1
41#endif
42
43FILE *
44esysdep_fopen (zfile, fpublic, fappend, fmkdirs)
45     const char *zfile;
46     boolean fpublic;
47     boolean fappend;
48     boolean fmkdirs;
49{
50  int imode;
51  int o;
52  FILE *e;
53  int force_chmod = 0;
54  char rfile[PATH_MAX];
55
56  if (fpublic)
57    imode = IPUBLIC_FILE_MODE;
58  else
59    imode = IPRIVATE_FILE_MODE;
60
61#ifdef WORLD_WRITABLE_FILE_IN
62  realpath(zfile, rfile);
63  if (rfile == strstr(rfile, WORLD_WRITABLE_FILE_IN)) {
64      imode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
65      force_chmod = 1;
66  }
67#endif
68
69  if (! fappend)
70    o = creat ((char *) zfile, imode);
71  else
72    {
73#ifdef O_CREAT
74      o = open ((char *) zfile,
75		O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY,
76		imode);
77#else
78      o = open ((char *) zfile, O_WRONLY | O_NOCTTY);
79      if (o < 0 && errno == ENOENT)
80	o = creat ((char *) zfile, imode);
81#endif /* ! defined (O_CREAT) */
82    }
83
84  if (o < 0)
85    {
86      if (errno == ENOENT && fmkdirs)
87	{
88	  if (! fsysdep_make_dirs (zfile, fpublic))
89	    return NULL;
90	  if (! fappend)
91	    o = creat ((char *) zfile, imode);
92	  else
93	    {
94#ifdef O_CREAT
95	      o = open ((char *) zfile,
96			O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY,
97			imode);
98#else
99	      o = creat ((char *) zfile, imode);
100#endif
101	    }
102	}
103      if (o < 0)
104	{
105	  ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
106	  if (errno == EPERM) {
107	      struct stat sb;
108	      o = stat(zfile, &sb);
109	      if (o == 0) {
110		  ulog(LOG_ERROR, "my uid %d; file uid %d, mode %o",
111		    getuid(), sb.st_uid, sb.st_mode);
112	      } else {
113		  ulog(LOG_ERROR, "can't stat %s", zfile);
114	      }
115	  }
116	  return NULL;
117	}
118    }
119
120#ifndef O_CREAT
121#ifdef O_APPEND
122  if (fappend)
123    {
124      if (fcntl (o, F_SETFL, O_APPEND) < 0)
125	{
126	  ulog (LOG_ERROR, "fcntl (%s, O_APPEND): %s", zfile,
127		strerror (errno));
128	  (void) close (o);
129	  return NULL;
130	}
131    }
132#endif /* defined (O_APPEND) */
133#endif /* ! defined (O_CREAT) */
134
135  if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
136    {
137      ulog (LOG_ERROR, "fcntl (%s, FD_CLOEXEC): %s", zfile,
138	    strerror (errno));
139      (void) close (o);
140      return NULL;
141    }
142
143  if (imode == IPUBLIC_FILE_MODE || force_chmod) {
144      e = fchmod(o, imode);
145      if (e) {
146	  ulog(LOG_ERROR, "fchmod %s %o %s", zfile, imode, strerror(errno));
147      }
148  }
149
150  if (fappend)
151    e = fdopen (o, (char *) "a");
152  else
153    e = fdopen (o, (char *) "w");
154
155  if (e == NULL)
156    {
157      ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
158      (void) close (o);
159    }
160
161  return e;
162}
163