]> git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/fileutils.c
hwclock: report rtc open() errors on --verbose
[thirdparty/util-linux.git] / lib / fileutils.c
1 /*
2 * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi>
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9 #include <sys/time.h>
10 #include <sys/resource.h>
11
12 #include "c.h"
13 #include "fileutils.h"
14 #include "pathnames.h"
15
16 int mkstemp_cloexec(char *template)
17 {
18 #ifdef HAVE_MKOSTEMP
19 return mkostemp(template, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC);
20 #else
21 int fd, old_flags, errno_save;
22
23 fd = mkstemp(template);
24 if (fd < 0)
25 return fd;
26
27 old_flags = fcntl(fd, F_GETFD, 0);
28 if (old_flags < 0)
29 goto unwind;
30 if (fcntl(fd, F_SETFD, old_flags | O_CLOEXEC) < 0)
31 goto unwind;
32
33 return fd;
34
35 unwind:
36 errno_save = errno;
37 unlink(template);
38 close(fd);
39 errno = errno_save;
40
41 return -1;
42 #endif
43 }
44
45 /* Create open temporary file in safe way. Please notice that the
46 * file permissions are -rw------- by default. */
47 int xmkstemp(char **tmpname, const char *dir, const char *prefix)
48 {
49 char *localtmp;
50 const char *tmpenv;
51 mode_t old_mode;
52 int fd, rc;
53
54 /* Some use cases must be capable of being moved atomically
55 * with rename(2), which is the reason why dir is here. */
56 tmpenv = dir ? dir : getenv("TMPDIR");
57 if (!tmpenv)
58 tmpenv = _PATH_TMP;
59
60 rc = asprintf(&localtmp, "%s/%s.XXXXXX", tmpenv, prefix);
61 if (rc < 0)
62 return -1;
63
64 old_mode = umask(077);
65 fd = mkstemp_cloexec(localtmp);
66 umask(old_mode);
67 if (fd == -1) {
68 free(localtmp);
69 localtmp = NULL;
70 }
71 *tmpname = localtmp;
72 return fd;
73 }
74
75 int dup_fd_cloexec(int oldfd, int lowfd)
76 {
77 int fd, flags, errno_save;
78
79 #ifdef F_DUPFD_CLOEXEC
80 fd = fcntl(oldfd, F_DUPFD_CLOEXEC, lowfd);
81 if (fd >= 0)
82 return fd;
83 #endif
84
85 fd = dup(oldfd);
86 if (fd < 0)
87 return fd;
88
89 flags = fcntl(fd, F_GETFD);
90 if (flags < 0)
91 goto unwind;
92 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
93 goto unwind;
94
95 return fd;
96
97 unwind:
98 errno_save = errno;
99 close(fd);
100 errno = errno_save;
101
102 return -1;
103 }
104
105 /*
106 * portable getdtablesize()
107 */
108 int get_fd_tabsize(void)
109 {
110 int m;
111
112 #if defined(HAVE_GETDTABLESIZE)
113 m = getdtablesize();
114 #elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
115 struct rlimit rl;
116
117 getrlimit(RLIMIT_NOFILE, &rl);
118 m = rl.rlim_cur;
119 #elif defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
120 m = sysconf(_SC_OPEN_MAX);
121 #else
122 m = OPEN_MAX;
123 #endif
124 return m;
125 }
126
127 #ifdef TEST_PROGRAM_FILEUTILS
128 int main(void)
129 {
130 FILE *f;
131 char *tmpname;
132 f = xfmkstemp(&tmpname, NULL, "test");
133 unlink(tmpname);
134 free(tmpname);
135 fclose(f);
136 return EXIT_FAILURE;
137 }
138 #endif
139
140
141 int mkdir_p(const char *path, mode_t mode)
142 {
143 char *p, *dir;
144 int rc = 0;
145
146 if (!path || !*path)
147 return -EINVAL;
148
149 dir = p = strdup(path);
150 if (!dir)
151 return -ENOMEM;
152
153 if (*p == '/')
154 p++;
155
156 while (p && *p) {
157 char *e = strchr(p, '/');
158 if (e)
159 *e = '\0';
160 if (*p) {
161 rc = mkdir(dir, mode);
162 if (rc && errno != EEXIST)
163 break;
164 rc = 0;
165 }
166 if (!e)
167 break;
168 *e = '/';
169 p = e + 1;
170 }
171
172 free(dir);
173 return rc;
174 }
175
176 /* returns basename and keeps dirname in the @path, if @path is "/" (root)
177 * then returns empty string */
178 char *stripoff_last_component(char *path)
179 {
180 char *p = path ? strrchr(path, '/') : NULL;
181
182 if (!p)
183 return NULL;
184 *p = '\0';
185 return p + 1;
186 }