/src/samba/lib/replace/replace.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | replacement routines for broken systems |
4 | | Copyright (C) Andrew Tridgell 1992-1998 |
5 | | Copyright (C) Jelmer Vernooij 2005-2008 |
6 | | Copyright (C) Matthieu Patou 2010 |
7 | | |
8 | | ** NOTE! The following LGPL license applies to the replace |
9 | | ** library. This does NOT imply that all of Samba is released |
10 | | ** under the LGPL |
11 | | |
12 | | This library is free software; you can redistribute it and/or |
13 | | modify it under the terms of the GNU Lesser General Public |
14 | | License as published by the Free Software Foundation; either |
15 | | version 3 of the License, or (at your option) any later version. |
16 | | |
17 | | This library is distributed in the hope that it will be useful, |
18 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
20 | | Lesser General Public License for more details. |
21 | | |
22 | | You should have received a copy of the GNU Lesser General Public |
23 | | License along with this library; if not, see <http://www.gnu.org/licenses/>. |
24 | | */ |
25 | | |
26 | | #include "replace.h" |
27 | | |
28 | | #include "system/filesys.h" |
29 | | #include "system/time.h" |
30 | | #include "system/network.h" |
31 | | #include "system/passwd.h" |
32 | | #include "system/syslog.h" |
33 | | #include "system/locale.h" |
34 | | #include "system/wait.h" |
35 | | |
36 | | #ifdef HAVE_SYS_SYSCALL_H |
37 | | #include <sys/syscall.h> |
38 | | #endif |
39 | | |
40 | | #ifdef HAVE_SYS_PRCTL_H |
41 | | #include <sys/prctl.h> |
42 | | #endif |
43 | | |
44 | | #ifdef _WIN32 |
45 | | #define mkdir(d,m) _mkdir(d) |
46 | | #endif |
47 | | |
48 | | void replace_dummy(void); |
49 | 0 | void replace_dummy(void) {} |
50 | | |
51 | | #ifndef HAVE_FTRUNCATE |
52 | | /******************************************************************* |
53 | | ftruncate for operating systems that don't have it |
54 | | ********************************************************************/ |
55 | | int rep_ftruncate(int f, off_t l) |
56 | | { |
57 | | #ifdef HAVE_CHSIZE |
58 | | return chsize(f,l); |
59 | | #elif defined(F_FREESP) |
60 | | struct flock fl; |
61 | | |
62 | | fl.l_whence = 0; |
63 | | fl.l_len = 0; |
64 | | fl.l_start = l; |
65 | | fl.l_type = F_WRLCK; |
66 | | return fcntl(f, F_FREESP, &fl); |
67 | | #else |
68 | | #error "you must have a ftruncate function" |
69 | | #endif |
70 | | } |
71 | | #endif /* HAVE_FTRUNCATE */ |
72 | | |
73 | | |
74 | | #ifndef HAVE_STRLCPY |
75 | | /* |
76 | | * Like strncpy but does not 0 fill the buffer and always null |
77 | | * terminates. bufsize is the size of the destination buffer. |
78 | | * Returns the length of s. |
79 | | */ |
80 | | size_t rep_strlcpy(char *d, const char *s, size_t bufsize) |
81 | | { |
82 | | size_t len = strlen(s); |
83 | | size_t ret = len; |
84 | | |
85 | | if (bufsize <= 0) { |
86 | | return 0; |
87 | | } |
88 | | if (len >= bufsize) { |
89 | | len = bufsize - 1; |
90 | | } |
91 | | memcpy(d, s, len); |
92 | | d[len] = 0; |
93 | | return ret; |
94 | | } |
95 | | #endif |
96 | | |
97 | | #ifndef HAVE_STRLCAT |
98 | | /* like strncat but does not 0 fill the buffer and always null |
99 | | terminates. bufsize is the length of the buffer, which should |
100 | | be one more than the maximum resulting string length */ |
101 | | size_t rep_strlcat(char *d, const char *s, size_t bufsize) |
102 | | { |
103 | | size_t len1 = strnlen(d, bufsize); |
104 | | size_t len2 = strlen(s); |
105 | | size_t ret = len1 + len2; |
106 | | |
107 | | if (len1+len2 >= bufsize) { |
108 | | if (bufsize < (len1+1)) { |
109 | | return ret; |
110 | | } |
111 | | len2 = bufsize - (len1+1); |
112 | | } |
113 | | if (len2 > 0) { |
114 | | memcpy(d+len1, s, len2); |
115 | | d[len1+len2] = 0; |
116 | | } |
117 | | return ret; |
118 | | } |
119 | | #endif |
120 | | |
121 | | #ifndef HAVE_MKTIME |
122 | | /******************************************************************* |
123 | | a mktime() replacement for those who don't have it - contributed by |
124 | | C.A. Lademann <cal@zls.com> |
125 | | Corrections by richard.kettlewell@kewill.com |
126 | | ********************************************************************/ |
127 | | |
128 | | #define MINUTE 60 |
129 | | #define HOUR 60*MINUTE |
130 | | #define DAY 24*HOUR |
131 | | #define YEAR 365*DAY |
132 | | time_t rep_mktime(struct tm *t) |
133 | | { |
134 | | struct tm *u; |
135 | | time_t epoch = 0; |
136 | | int n; |
137 | | int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, |
138 | | y, m, i; |
139 | | |
140 | | if(t->tm_year < 70) |
141 | | return((time_t)-1); |
142 | | |
143 | | n = t->tm_year + 1900 - 1; |
144 | | epoch = (t->tm_year - 70) * YEAR + |
145 | | ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY; |
146 | | |
147 | | y = t->tm_year + 1900; |
148 | | m = 0; |
149 | | |
150 | | for(i = 0; i < t->tm_mon; i++) { |
151 | | epoch += mon [m] * DAY; |
152 | | if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) |
153 | | epoch += DAY; |
154 | | |
155 | | if(++m > 11) { |
156 | | m = 0; |
157 | | y++; |
158 | | } |
159 | | } |
160 | | |
161 | | epoch += (t->tm_mday - 1) * DAY; |
162 | | epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec; |
163 | | |
164 | | if((u = localtime(&epoch)) != NULL) { |
165 | | t->tm_sec = u->tm_sec; |
166 | | t->tm_min = u->tm_min; |
167 | | t->tm_hour = u->tm_hour; |
168 | | t->tm_mday = u->tm_mday; |
169 | | t->tm_mon = u->tm_mon; |
170 | | t->tm_year = u->tm_year; |
171 | | t->tm_wday = u->tm_wday; |
172 | | t->tm_yday = u->tm_yday; |
173 | | t->tm_isdst = u->tm_isdst; |
174 | | } |
175 | | |
176 | | return(epoch); |
177 | | } |
178 | | #endif /* !HAVE_MKTIME */ |
179 | | |
180 | | |
181 | | #ifndef HAVE_INITGROUPS |
182 | | /**************************************************************************** |
183 | | some systems don't have an initgroups call |
184 | | ****************************************************************************/ |
185 | | int rep_initgroups(char *name, gid_t id) |
186 | | { |
187 | | #ifndef HAVE_SETGROUPS |
188 | | /* yikes! no SETGROUPS or INITGROUPS? how can this work? */ |
189 | | errno = ENOSYS; |
190 | | return -1; |
191 | | #else /* HAVE_SETGROUPS */ |
192 | | |
193 | | #include <grp.h> |
194 | | |
195 | | gid_t *grouplst = NULL; |
196 | | int max_gr = NGROUPS_MAX; |
197 | | int ret; |
198 | | int i,j; |
199 | | struct group *g; |
200 | | char *gr; |
201 | | |
202 | | if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) { |
203 | | errno = ENOMEM; |
204 | | return -1; |
205 | | } |
206 | | |
207 | | grouplst[0] = id; |
208 | | i = 1; |
209 | | while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) { |
210 | | if (g->gr_gid == id) |
211 | | continue; |
212 | | j = 0; |
213 | | gr = g->gr_mem[0]; |
214 | | while (gr && (*gr != (char)NULL)) { |
215 | | if (strcmp(name,gr) == 0) { |
216 | | grouplst[i] = g->gr_gid; |
217 | | i++; |
218 | | gr = (char *)NULL; |
219 | | break; |
220 | | } |
221 | | gr = g->gr_mem[++j]; |
222 | | } |
223 | | } |
224 | | endgrent(); |
225 | | ret = setgroups(i, grouplst); |
226 | | free(grouplst); |
227 | | return ret; |
228 | | #endif /* HAVE_SETGROUPS */ |
229 | | } |
230 | | #endif /* HAVE_INITGROUPS */ |
231 | | |
232 | | |
233 | | #ifndef HAVE_MEMMOVE |
234 | | /******************************************************************* |
235 | | safely copies memory, ensuring no overlap problems. |
236 | | this is only used if the machine does not have its own memmove(). |
237 | | this is not the fastest algorithm in town, but it will do for our |
238 | | needs. |
239 | | ********************************************************************/ |
240 | | void *rep_memmove(void *dest,const void *src,int size) |
241 | | { |
242 | | unsigned long d,s; |
243 | | int i; |
244 | | if (dest==src || !size) return(dest); |
245 | | |
246 | | d = (unsigned long)dest; |
247 | | s = (unsigned long)src; |
248 | | |
249 | | if ((d >= (s+size)) || (s >= (d+size))) { |
250 | | /* no overlap */ |
251 | | memcpy(dest,src,size); |
252 | | return(dest); |
253 | | } |
254 | | |
255 | | if (d < s) { |
256 | | /* we can forward copy */ |
257 | | if (s-d >= sizeof(int) && |
258 | | !(s%sizeof(int)) && |
259 | | !(d%sizeof(int)) && |
260 | | !(size%sizeof(int))) { |
261 | | /* do it all as words */ |
262 | | int *idest = (int *)dest; |
263 | | int *isrc = (int *)src; |
264 | | size /= sizeof(int); |
265 | | for (i=0;i<size;i++) idest[i] = isrc[i]; |
266 | | } else { |
267 | | /* simplest */ |
268 | | char *cdest = (char *)dest; |
269 | | char *csrc = (char *)src; |
270 | | for (i=0;i<size;i++) cdest[i] = csrc[i]; |
271 | | } |
272 | | } else { |
273 | | /* must backward copy */ |
274 | | if (d-s >= sizeof(int) && |
275 | | !(s%sizeof(int)) && |
276 | | !(d%sizeof(int)) && |
277 | | !(size%sizeof(int))) { |
278 | | /* do it all as words */ |
279 | | int *idest = (int *)dest; |
280 | | int *isrc = (int *)src; |
281 | | size /= sizeof(int); |
282 | | for (i=size-1;i>=0;i--) idest[i] = isrc[i]; |
283 | | } else { |
284 | | /* simplest */ |
285 | | char *cdest = (char *)dest; |
286 | | char *csrc = (char *)src; |
287 | | for (i=size-1;i>=0;i--) cdest[i] = csrc[i]; |
288 | | } |
289 | | } |
290 | | return(dest); |
291 | | } |
292 | | #endif /* HAVE_MEMMOVE */ |
293 | | |
294 | | #ifndef HAVE_STRDUP |
295 | | /**************************************************************************** |
296 | | duplicate a string |
297 | | ****************************************************************************/ |
298 | | char *rep_strdup(const char *s) |
299 | | { |
300 | | size_t len; |
301 | | char *ret; |
302 | | |
303 | | if (!s) return(NULL); |
304 | | |
305 | | len = strlen(s)+1; |
306 | | ret = (char *)malloc(len); |
307 | | if (!ret) return(NULL); |
308 | | memcpy(ret,s,len); |
309 | | return(ret); |
310 | | } |
311 | | #endif /* HAVE_STRDUP */ |
312 | | |
313 | | #ifndef HAVE_SETLINEBUF |
314 | | void rep_setlinebuf(FILE *stream) |
315 | | { |
316 | | setvbuf(stream, (char *)NULL, _IOLBF, 0); |
317 | | } |
318 | | #endif /* HAVE_SETLINEBUF */ |
319 | | |
320 | | #ifndef HAVE_VSYSLOG |
321 | | #ifdef HAVE_SYSLOG |
322 | | void rep_vsyslog (int facility_priority, const char *format, va_list arglist) |
323 | | { |
324 | | char *msg = NULL; |
325 | | vasprintf(&msg, format, arglist); |
326 | | if (!msg) |
327 | | return; |
328 | | syslog(facility_priority, "%s", msg); |
329 | | free(msg); |
330 | | } |
331 | | #endif /* HAVE_SYSLOG */ |
332 | | #endif /* HAVE_VSYSLOG */ |
333 | | |
334 | | #ifndef HAVE_STRNLEN |
335 | | /** |
336 | | Some platforms don't have strnlen |
337 | | **/ |
338 | | size_t rep_strnlen(const char *s, size_t max) |
339 | | { |
340 | | size_t len; |
341 | | |
342 | | for (len = 0; len < max; len++) { |
343 | | if (s[len] == '\0') { |
344 | | break; |
345 | | } |
346 | | } |
347 | | return len; |
348 | | } |
349 | | #endif |
350 | | |
351 | | #ifndef HAVE_STRNDUP |
352 | | /** |
353 | | Some platforms don't have strndup. |
354 | | **/ |
355 | | char *rep_strndup(const char *s, size_t n) |
356 | | { |
357 | | char *ret; |
358 | | |
359 | | n = strnlen(s, n); |
360 | | ret = malloc(n+1); |
361 | | if (!ret) |
362 | | return NULL; |
363 | | memcpy(ret, s, n); |
364 | | ret[n] = 0; |
365 | | |
366 | | return ret; |
367 | | } |
368 | | #endif |
369 | | |
370 | | #if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4) |
371 | | int rep_waitpid(pid_t pid,int *status,int options) |
372 | | { |
373 | | return wait4(pid, status, options, NULL); |
374 | | } |
375 | | #endif |
376 | | |
377 | | #ifndef HAVE_SETEUID |
378 | | int rep_seteuid(uid_t euid) |
379 | | { |
380 | | #ifdef HAVE_SETRESUID |
381 | | return setresuid(-1, euid, -1); |
382 | | #else |
383 | | errno = ENOSYS; |
384 | | return -1; |
385 | | #endif |
386 | | } |
387 | | #endif |
388 | | |
389 | | #ifndef HAVE_SETEGID |
390 | | int rep_setegid(gid_t egid) |
391 | | { |
392 | | #ifdef HAVE_SETRESGID |
393 | | return setresgid(-1, egid, -1); |
394 | | #else |
395 | | errno = ENOSYS; |
396 | | return -1; |
397 | | #endif |
398 | | } |
399 | | #endif |
400 | | |
401 | | /******************************************************************* |
402 | | os/2 also doesn't have chroot |
403 | | ********************************************************************/ |
404 | | #ifndef HAVE_CHROOT |
405 | | int rep_chroot(const char *dname) |
406 | | { |
407 | | errno = ENOSYS; |
408 | | return -1; |
409 | | } |
410 | | #endif |
411 | | |
412 | | /***************************************************************** |
413 | | Possibly replace mkstemp if it is broken. |
414 | | *****************************************************************/ |
415 | | |
416 | | #ifndef HAVE_SECURE_MKSTEMP |
417 | | int rep_mkstemp(char *template) |
418 | | { |
419 | | /* have a reasonable go at emulating it. Hope that |
420 | | the system mktemp() isn't completely hopeless */ |
421 | | mktemp(template); |
422 | | if (template[0] == 0) |
423 | | return -1; |
424 | | return open(template, O_CREAT|O_EXCL|O_RDWR, 0600); |
425 | | } |
426 | | #endif |
427 | | |
428 | | #ifndef HAVE_MKDTEMP |
429 | | char *rep_mkdtemp(char *template) |
430 | | { |
431 | | char *dname; |
432 | | |
433 | | if ((dname = mktemp(template))) { |
434 | | if (mkdir(dname, 0700) >= 0) { |
435 | | return dname; |
436 | | } |
437 | | } |
438 | | |
439 | | return NULL; |
440 | | } |
441 | | #endif |
442 | | |
443 | | /***************************************************************** |
444 | | Watch out: this is not thread safe. |
445 | | *****************************************************************/ |
446 | | |
447 | | #ifndef HAVE_PREAD |
448 | | ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset) |
449 | | { |
450 | | if (lseek(__fd, __offset, SEEK_SET) != __offset) { |
451 | | return -1; |
452 | | } |
453 | | return read(__fd, __buf, __nbytes); |
454 | | } |
455 | | #endif |
456 | | |
457 | | /***************************************************************** |
458 | | Watch out: this is not thread safe. |
459 | | *****************************************************************/ |
460 | | |
461 | | #ifndef HAVE_PWRITE |
462 | | ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset) |
463 | | { |
464 | | if (lseek(__fd, __offset, SEEK_SET) != __offset) { |
465 | | return -1; |
466 | | } |
467 | | return write(__fd, __buf, __nbytes); |
468 | | } |
469 | | #endif |
470 | | |
471 | | #ifndef HAVE_STRCASESTR |
472 | | char *rep_strcasestr(const char *haystack, const char *needle) |
473 | | { |
474 | | const char *s; |
475 | | size_t nlen = strlen(needle); |
476 | | for (s=haystack;*s;s++) { |
477 | | if (toupper(*needle) == toupper(*s) && |
478 | | strncasecmp(s, needle, nlen) == 0) { |
479 | | return (char *)((uintptr_t)s); |
480 | | } |
481 | | } |
482 | | return NULL; |
483 | | } |
484 | | #endif |
485 | | |
486 | | #ifndef HAVE_STRSEP |
487 | | char *rep_strsep(char **pps, const char *delim) |
488 | | { |
489 | | char *ret = *pps; |
490 | | char *p = *pps; |
491 | | |
492 | | if (p == NULL) { |
493 | | return NULL; |
494 | | } |
495 | | p += strcspn(p, delim); |
496 | | if (*p == '\0') { |
497 | | *pps = NULL; |
498 | | } else { |
499 | | *p = '\0'; |
500 | | *pps = p + 1; |
501 | | } |
502 | | return ret; |
503 | | } |
504 | | #endif |
505 | | |
506 | | #ifndef HAVE_STRTOK_R |
507 | | /* based on GLIBC version, copyright Free Software Foundation */ |
508 | | char *rep_strtok_r(char *s, const char *delim, char **save_ptr) |
509 | | { |
510 | | char *token; |
511 | | |
512 | | if (s == NULL) s = *save_ptr; |
513 | | |
514 | | s += strspn(s, delim); |
515 | | if (*s == '\0') { |
516 | | *save_ptr = s; |
517 | | return NULL; |
518 | | } |
519 | | |
520 | | token = s; |
521 | | s = strpbrk(token, delim); |
522 | | if (s == NULL) { |
523 | | *save_ptr = token + strlen(token); |
524 | | } else { |
525 | | *s = '\0'; |
526 | | *save_ptr = s + 1; |
527 | | } |
528 | | |
529 | | return token; |
530 | | } |
531 | | #endif |
532 | | |
533 | | |
534 | | #ifndef HAVE_STRTOLL |
535 | | long long int rep_strtoll(const char *str, char **endptr, int base) |
536 | | { |
537 | | #ifdef HAVE_STRTOQ |
538 | | return strtoq(str, endptr, base); |
539 | | #elif defined(HAVE___STRTOLL) |
540 | | return __strtoll(str, endptr, base); |
541 | | #elif SIZEOF_LONG == SIZEOF_LONG_LONG |
542 | | return (long long int) strtol(str, endptr, base); |
543 | | #else |
544 | | # error "You need a strtoll function" |
545 | | #endif |
546 | | } |
547 | | #else |
548 | | #ifdef HAVE_BSD_STRTOLL |
549 | | #undef strtoll |
550 | | long long int rep_strtoll(const char *str, char **endptr, int base) |
551 | | { |
552 | | int saved_errno = errno; |
553 | | long long int nb = strtoll(str, endptr, base); |
554 | | /* With glibc EINVAL is only returned if base is not ok */ |
555 | | if (errno == EINVAL) { |
556 | | if (base == 0 || (base >1 && base <37)) { |
557 | | /* Base was ok so it's because we were not |
558 | | * able to make the conversion. |
559 | | * Let's reset errno. |
560 | | */ |
561 | | errno = saved_errno; |
562 | | } |
563 | | } |
564 | | return nb; |
565 | | } |
566 | | #endif /* HAVE_BSD_STRTOLL */ |
567 | | #endif /* HAVE_STRTOLL */ |
568 | | |
569 | | |
570 | | #ifndef HAVE_STRTOULL |
571 | | unsigned long long int rep_strtoull(const char *str, char **endptr, int base) |
572 | | { |
573 | | #ifdef HAVE_STRTOUQ |
574 | | return strtouq(str, endptr, base); |
575 | | #elif defined(HAVE___STRTOULL) |
576 | | return __strtoull(str, endptr, base); |
577 | | #elif SIZEOF_LONG == SIZEOF_LONG_LONG |
578 | | return (unsigned long long int) strtoul(str, endptr, base); |
579 | | #else |
580 | | # error "You need a strtoull function" |
581 | | #endif |
582 | | } |
583 | | #else |
584 | | #ifdef HAVE_BSD_STRTOLL |
585 | | #undef strtoull |
586 | | unsigned long long int rep_strtoull(const char *str, char **endptr, int base) |
587 | | { |
588 | | int saved_errno = errno; |
589 | | unsigned long long int nb = strtoull(str, endptr, base); |
590 | | /* With glibc EINVAL is only returned if base is not ok */ |
591 | | if (errno == EINVAL) { |
592 | | if (base == 0 || (base >1 && base <37)) { |
593 | | /* Base was ok so it's because we were not |
594 | | * able to make the conversion. |
595 | | * Let's reset errno. |
596 | | */ |
597 | | errno = saved_errno; |
598 | | } |
599 | | } |
600 | | return nb; |
601 | | } |
602 | | #endif /* HAVE_BSD_STRTOLL */ |
603 | | #endif /* HAVE_STRTOULL */ |
604 | | |
605 | | #ifndef HAVE_SETENV |
606 | | int rep_setenv(const char *name, const char *value, int overwrite) |
607 | | { |
608 | | char *p; |
609 | | size_t l1, l2; |
610 | | int ret; |
611 | | |
612 | | if (!overwrite && getenv(name)) { |
613 | | return 0; |
614 | | } |
615 | | |
616 | | l1 = strlen(name); |
617 | | l2 = strlen(value); |
618 | | |
619 | | p = malloc(l1+l2+2); |
620 | | if (p == NULL) { |
621 | | return -1; |
622 | | } |
623 | | memcpy(p, name, l1); |
624 | | p[l1] = '='; |
625 | | memcpy(p+l1+1, value, l2); |
626 | | p[l1+l2+1] = 0; |
627 | | |
628 | | ret = putenv(p); |
629 | | if (ret != 0) { |
630 | | free(p); |
631 | | } |
632 | | |
633 | | return ret; |
634 | | } |
635 | | #endif |
636 | | |
637 | | #ifndef HAVE_UNSETENV |
638 | | int rep_unsetenv(const char *name) |
639 | | { |
640 | | extern char **environ; |
641 | | size_t len = strlen(name); |
642 | | size_t i, count; |
643 | | |
644 | | if (environ == NULL || getenv(name) == NULL) { |
645 | | return 0; |
646 | | } |
647 | | |
648 | | for (i=0;environ[i];i++) /* noop */ ; |
649 | | |
650 | | count=i; |
651 | | |
652 | | for (i=0;i<count;) { |
653 | | if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') { |
654 | | /* note: we do _not_ free the old variable here. It is unsafe to |
655 | | do so, as the pointer may not have come from malloc */ |
656 | | memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *)); |
657 | | count--; |
658 | | } else { |
659 | | i++; |
660 | | } |
661 | | } |
662 | | |
663 | | return 0; |
664 | | } |
665 | | #endif |
666 | | |
667 | | #ifndef HAVE_UTIME |
668 | | int rep_utime(const char *filename, const struct utimbuf *buf) |
669 | | { |
670 | | errno = ENOSYS; |
671 | | return -1; |
672 | | } |
673 | | #endif |
674 | | |
675 | | #ifndef HAVE_UTIMES |
676 | | int rep_utimes(const char *filename, const struct timeval tv[2]) |
677 | | { |
678 | | struct utimbuf u; |
679 | | |
680 | | u.actime = tv[0].tv_sec; |
681 | | if (tv[0].tv_usec > 500000) { |
682 | | u.actime += 1; |
683 | | } |
684 | | |
685 | | u.modtime = tv[1].tv_sec; |
686 | | if (tv[1].tv_usec > 500000) { |
687 | | u.modtime += 1; |
688 | | } |
689 | | |
690 | | return utime(filename, &u); |
691 | | } |
692 | | #endif |
693 | | |
694 | | #ifndef HAVE_DUP2 |
695 | | int rep_dup2(int oldfd, int newfd) |
696 | | { |
697 | | errno = ENOSYS; |
698 | | return -1; |
699 | | } |
700 | | #endif |
701 | | |
702 | | #ifndef HAVE_CHOWN |
703 | | /** |
704 | | chown isn't used much but OS/2 doesn't have it |
705 | | **/ |
706 | | int rep_chown(const char *fname, uid_t uid, gid_t gid) |
707 | | { |
708 | | errno = ENOSYS; |
709 | | return -1; |
710 | | } |
711 | | #endif |
712 | | |
713 | | #ifndef HAVE_LINK |
714 | | int rep_link(const char *oldpath, const char *newpath) |
715 | | { |
716 | | errno = ENOSYS; |
717 | | return -1; |
718 | | } |
719 | | #endif |
720 | | |
721 | | #ifndef HAVE_READLINK |
722 | | int rep_readlink(const char *path, char *buf, size_t bufsiz) |
723 | | { |
724 | | errno = ENOSYS; |
725 | | return -1; |
726 | | } |
727 | | #endif |
728 | | |
729 | | #ifndef HAVE_SYMLINK |
730 | | int rep_symlink(const char *oldpath, const char *newpath) |
731 | | { |
732 | | errno = ENOSYS; |
733 | | return -1; |
734 | | } |
735 | | #endif |
736 | | |
737 | | #ifndef HAVE_LCHOWN |
738 | | int rep_lchown(const char *fname,uid_t uid,gid_t gid) |
739 | | { |
740 | | errno = ENOSYS; |
741 | | return -1; |
742 | | } |
743 | | #endif |
744 | | |
745 | | #ifndef HAVE_REALPATH |
746 | | char *rep_realpath(const char *path, char *resolved_path) |
747 | | { |
748 | | /* As realpath is not a system call we can't return ENOSYS. */ |
749 | | errno = EINVAL; |
750 | | return NULL; |
751 | | } |
752 | | #endif |
753 | | |
754 | | |
755 | | #ifndef HAVE_MEMMEM |
756 | | void *rep_memmem(const void *haystack, size_t haystacklen, |
757 | | const void *needle, size_t needlelen) |
758 | | { |
759 | | if (needlelen == 0) { |
760 | | return discard_const(haystack); |
761 | | } |
762 | | while (haystacklen >= needlelen) { |
763 | | char *p = (char *)memchr(haystack, *(const char *)needle, |
764 | | haystacklen-(needlelen-1)); |
765 | | if (!p) return NULL; |
766 | | if (memcmp(p, needle, needlelen) == 0) { |
767 | | return p; |
768 | | } |
769 | | haystack = p+1; |
770 | | haystacklen -= (p - (const char *)haystack) + 1; |
771 | | } |
772 | | return NULL; |
773 | | } |
774 | | #endif |
775 | | |
776 | | #if !defined(HAVE_VDPRINTF) || !defined(HAVE_C99_VSNPRINTF) |
777 | | int rep_vdprintf(int fd, const char *format, va_list ap) |
778 | | { |
779 | | char *s = NULL; |
780 | | int ret; |
781 | | |
782 | | vasprintf(&s, format, ap); |
783 | | if (s == NULL) { |
784 | | errno = ENOMEM; |
785 | | return -1; |
786 | | } |
787 | | ret = write(fd, s, strlen(s)); |
788 | | free(s); |
789 | | return ret; |
790 | | } |
791 | | #endif |
792 | | |
793 | | #if !defined(HAVE_DPRINTF) || !defined(HAVE_C99_VSNPRINTF) |
794 | | int rep_dprintf(int fd, const char *format, ...) |
795 | | { |
796 | | int ret; |
797 | | va_list ap; |
798 | | |
799 | | va_start(ap, format); |
800 | | ret = vdprintf(fd, format, ap); |
801 | | va_end(ap); |
802 | | |
803 | | return ret; |
804 | | } |
805 | | #endif |
806 | | |
807 | | #ifndef HAVE_GET_CURRENT_DIR_NAME |
808 | | char *rep_get_current_dir_name(void) |
809 | | { |
810 | | char buf[PATH_MAX+1]; |
811 | | char *p; |
812 | | p = getcwd(buf, sizeof(buf)); |
813 | | if (p == NULL) { |
814 | | return NULL; |
815 | | } |
816 | | return strdup(p); |
817 | | } |
818 | | #endif |
819 | | |
820 | | #ifndef HAVE_STRERROR_R |
821 | | int rep_strerror_r(int errnum, char *buf, size_t buflen) |
822 | | { |
823 | | char *s = strerror(errnum); |
824 | | if (strlen(s)+1 > buflen) { |
825 | | errno = ERANGE; |
826 | | return -1; |
827 | | } |
828 | | strncpy(buf, s, buflen); |
829 | | return 0; |
830 | | } |
831 | | #elif (!defined(STRERROR_R_XSI_NOT_GNU)) |
832 | | #undef strerror_r |
833 | | int rep_strerror_r(int errnum, char *buf, size_t buflen) |
834 | 0 | { |
835 | 0 | char *s = strerror_r(errnum, buf, buflen); |
836 | 0 | if (s == NULL) { |
837 | | /* Shouldn't happen, should always get a string */ |
838 | 0 | return EINVAL; |
839 | 0 | } |
840 | 0 | if (s != buf) { |
841 | 0 | strlcpy(buf, s, buflen); |
842 | 0 | if (strlen(s) > buflen - 1) { |
843 | 0 | return ERANGE; |
844 | 0 | } |
845 | 0 | } |
846 | 0 | return 0; |
847 | |
|
848 | 0 | } |
849 | | #endif |
850 | | |
851 | | #ifndef HAVE_CLOCK_GETTIME |
852 | | int rep_clock_gettime(clockid_t clk_id, struct timespec *tp) |
853 | | { |
854 | | struct timeval tval; |
855 | | switch (clk_id) { |
856 | | case 0: /* CLOCK_REALTIME :*/ |
857 | | #if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID) |
858 | | gettimeofday(&tval,NULL); |
859 | | #else |
860 | | gettimeofday(&tval); |
861 | | #endif |
862 | | tp->tv_sec = tval.tv_sec; |
863 | | tp->tv_nsec = tval.tv_usec * 1000; |
864 | | break; |
865 | | default: |
866 | | errno = EINVAL; |
867 | | return -1; |
868 | | } |
869 | | return 0; |
870 | | } |
871 | | #endif |
872 | | |
873 | | #ifndef HAVE_MEMALIGN |
874 | | void *rep_memalign( size_t align, size_t size ) |
875 | | { |
876 | | #if defined(HAVE_POSIX_MEMALIGN) |
877 | | void *p = NULL; |
878 | | int ret = posix_memalign( &p, align, size ); |
879 | | if ( ret == 0 ) |
880 | | return p; |
881 | | |
882 | | return NULL; |
883 | | #else |
884 | | /* On *BSD systems memaligns doesn't exist, but memory will |
885 | | * be aligned on allocations of > pagesize. */ |
886 | | #if defined(SYSCONF_SC_PAGESIZE) |
887 | | size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); |
888 | | #elif defined(HAVE_GETPAGESIZE) |
889 | | size_t pagesize = (size_t)getpagesize(); |
890 | | #else |
891 | | size_t pagesize = (size_t)-1; |
892 | | #endif |
893 | | if (pagesize == (size_t)-1) { |
894 | | errno = ENOSYS; |
895 | | return NULL; |
896 | | } |
897 | | if (size < pagesize) { |
898 | | size = pagesize; |
899 | | } |
900 | | return malloc(size); |
901 | | #endif |
902 | | } |
903 | | #endif |
904 | | |
905 | | #ifndef HAVE_GETPEEREID |
906 | | int rep_getpeereid(int s, uid_t *uid, gid_t *gid) |
907 | | { |
908 | | #if defined(HAVE_PEERCRED) |
909 | | struct ucred cred; |
910 | | socklen_t cred_len = sizeof(struct ucred); |
911 | | int ret; |
912 | | |
913 | | #undef getsockopt |
914 | | ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len); |
915 | | if (ret != 0) { |
916 | | return -1; |
917 | | } |
918 | | |
919 | | if (cred_len != sizeof(struct ucred)) { |
920 | | errno = EINVAL; |
921 | | return -1; |
922 | | } |
923 | | |
924 | | *uid = cred.uid; |
925 | | *gid = cred.gid; |
926 | | return 0; |
927 | | #else |
928 | | errno = ENOSYS; |
929 | | return -1; |
930 | | #endif |
931 | | } |
932 | | #endif |
933 | | |
934 | | #ifndef HAVE_USLEEP |
935 | | int rep_usleep(useconds_t sec) |
936 | | { |
937 | | struct timeval tval; |
938 | | /* |
939 | | * Fake it with select... |
940 | | */ |
941 | | tval.tv_sec = 0; |
942 | | tval.tv_usec = usecs/1000; |
943 | | select(0,NULL,NULL,NULL,&tval); |
944 | | return 0; |
945 | | } |
946 | | #endif /* HAVE_USLEEP */ |
947 | | |
948 | | #ifndef HAVE_SETPROCTITLE |
949 | | void rep_setproctitle(const char *fmt, ...) |
950 | | { |
951 | | #if defined(HAVE_PRCTL) && defined(PR_SET_MM_MAP) && defined(__NR_brk) |
952 | | /* |
953 | | * Implementation based on setproctitle from lcx under LGPL-2.1+ |
954 | | * https://github.com/lxc/lxc/ |
955 | | * |
956 | | * Using PR_SET_MM_MAP requires CAP_SYS_RESOURCE. |
957 | | */ |
958 | | static char *proctitle = NULL; |
959 | | char *tmp_proctitle = NULL; |
960 | | char buf[2048] = {0}; |
961 | | char title[2048] = {0}; |
962 | | va_list ap; |
963 | | char *ptr = NULL; |
964 | | FILE *f = NULL; |
965 | | size_t title_len; |
966 | | int ret = 0; |
967 | | struct prctl_mm_map prctl_map = { |
968 | | .exe_fd = -1, |
969 | | }; |
970 | | long brk_val = 0; |
971 | | /* See `man proc_pid_stat.5` */ |
972 | | unsigned long start_code = 0; // 26 |
973 | | unsigned long end_code = 0; // 27 |
974 | | unsigned long start_stack = 0; // 28 |
975 | | |
976 | | unsigned long start_data = 0; // 45 |
977 | | unsigned long end_data = 0; // 46 |
978 | | unsigned long start_brk = 0; // 47 |
979 | | unsigned long arg_start = 0; // 48 |
980 | | unsigned long arg_end = 0; // 49 |
981 | | unsigned long env_start = 0; // 50 |
982 | | unsigned long env_end = 0; // 51 |
983 | | |
984 | | f = fopen("/proc/self/stat", "r"); |
985 | | if (f == NULL) { |
986 | | return; |
987 | | } |
988 | | |
989 | | ptr = fgets(buf, sizeof(buf), f); |
990 | | fclose(f); |
991 | | if (ptr == NULL) { |
992 | | return; |
993 | | } |
994 | | |
995 | | /* |
996 | | * Find the last ')' to skip the comm field which can contain spaces and |
997 | | * maybe ')'. |
998 | | */ |
999 | | ptr = strrchr(buf, ')'); |
1000 | | if (ptr == NULL || ptr[1] == '\0') { |
1001 | | return; |
1002 | | } |
1003 | | ptr += 2; // Skip ') ' |
1004 | | |
1005 | | /* See `man proc_pid_stat.5` */ |
1006 | | ret = sscanf( |
1007 | | ptr, |
1008 | | "%*c " // 3 (state) |
1009 | | "%*d " // 4 (ppid) |
1010 | | "%*d " // 5 (pgrp) |
1011 | | "%*d " // 6 (session) |
1012 | | "%*d " // 7 (tty_nr) |
1013 | | "%*d " // 8 (tpgid) |
1014 | | "%*u " // 9 (flags) |
1015 | | "%*u " // 10 (minflt) |
1016 | | "%*u " // 11 (cminflt) |
1017 | | "%*u " // 12 (majflt) |
1018 | | "%*u " // 13 (cmajflt) |
1019 | | "%*u " // 14 (utime) |
1020 | | "%*u " // 15 (stime) |
1021 | | "%*d " // 16 (cutime) |
1022 | | "%*d " // 17 (cstime) |
1023 | | "%*d " // 18 (priority) |
1024 | | "%*d " // 19 (nice) |
1025 | | "%*d " // 20 (num_threads) |
1026 | | "%*d " // 21 (itrealvalue) |
1027 | | "%*u " // 22 (starttime) |
1028 | | "%*u " // 23 (vsize) |
1029 | | "%*d " // 24 (rss) |
1030 | | "%*u " // 25 (rsslim) |
1031 | | "%lu " // 26 (start_code) |
1032 | | "%lu " // 27 (end_code) |
1033 | | "%lu " // 28 (start_stack) |
1034 | | "%*u " // 29 (kstkesp) |
1035 | | "%*u " // 30 (kstkeip) |
1036 | | "%*u " // 31 (signal) |
1037 | | "%*u " // 32 (blocked) |
1038 | | "%*u " // 33 (sigignore) |
1039 | | "%*u " // 34 (sigcatch) |
1040 | | "%*u " // 35 (wchan) |
1041 | | "%*u " // 36 (nswap) |
1042 | | "%*u " // 37 (cnswap) |
1043 | | "%*d " // 38 (exit_signal) |
1044 | | "%*d " // 39 (processor) |
1045 | | "%*d " // 40 (rt_priority) |
1046 | | "%*u " // 41 (policy) |
1047 | | "%*u " // 42 (delayacct_blkio_ticks) |
1048 | | "%*u " // 43 (guest_time) |
1049 | | "%*d " // 44 (cguest_time) |
1050 | | "%lu " // 45 (start_data) |
1051 | | "%lu " // 46 (end_data) |
1052 | | "%lu " // 47 (start_brk) |
1053 | | "%lu " // 48 (arg_start) |
1054 | | "%lu " // 49 (arg_end) |
1055 | | "%lu " // 50 (env_start) |
1056 | | "%lu", // 51 (env_end) |
1057 | | &start_code, // 26 |
1058 | | &end_code, // 27 |
1059 | | &start_stack, // 28 |
1060 | | &start_data, // 45 |
1061 | | &end_data, // 46 |
1062 | | &start_brk, // 47 |
1063 | | &arg_start, // 48 |
1064 | | &arg_end, // 49 |
1065 | | &env_start, // 50 |
1066 | | &env_end // 51 |
1067 | | ); |
1068 | | if (ret != 10) { |
1069 | | return; |
1070 | | } |
1071 | | |
1072 | | va_start(ap, fmt); |
1073 | | ret = vsnprintf(title, sizeof(title), fmt, ap); |
1074 | | va_end(ap); |
1075 | | if (ret <= 0) { |
1076 | | return; |
1077 | | } |
1078 | | /* |
1079 | | * Include the null byte here, because in the calculations below |
1080 | | * we want to have room for it. |
1081 | | */ |
1082 | | title_len = ret + 1; |
1083 | | |
1084 | | /* This will leak memory */ |
1085 | | tmp_proctitle = realloc(proctitle, title_len); |
1086 | | if (tmp_proctitle == NULL) { |
1087 | | return; |
1088 | | } |
1089 | | proctitle = tmp_proctitle; |
1090 | | |
1091 | | arg_start = (uint64_t)proctitle; |
1092 | | arg_end = arg_start + title_len; |
1093 | | |
1094 | | brk_val = syscall(__NR_brk, 0); |
1095 | | if (brk_val < 0) { |
1096 | | return; |
1097 | | } |
1098 | | |
1099 | | prctl_map = (struct prctl_mm_map) { |
1100 | | .start_code = start_code, |
1101 | | .end_code = end_code, |
1102 | | .start_stack = start_stack, |
1103 | | .start_data = start_data, |
1104 | | .end_data = end_data, |
1105 | | .start_brk = start_brk, |
1106 | | .brk = brk_val, |
1107 | | .arg_start = arg_start, |
1108 | | .arg_end = arg_end, |
1109 | | .env_start = env_start, |
1110 | | .env_end = env_end, |
1111 | | .auxv = NULL, |
1112 | | .auxv_size = 0, |
1113 | | .exe_fd = -1, |
1114 | | }; |
1115 | | |
1116 | | ret = prctl(PR_SET_MM, |
1117 | | PR_SET_MM_MAP, |
1118 | | (long)&prctl_map, |
1119 | | sizeof(prctl_map), |
1120 | | 0); |
1121 | | if (ret == 0) { |
1122 | | strlcpy((char *)arg_start, title, title_len); |
1123 | | } |
1124 | | #endif /* HAVE_PRCTL */ |
1125 | | } |
1126 | | #endif |
1127 | | |
1128 | | #ifndef HAVE_SETPROCTITLE_INIT |
1129 | | void rep_setproctitle_init(int argc, char *argv[], char *envp[]) |
1130 | | { |
1131 | | } |
1132 | | #endif |
1133 | | |
1134 | | #ifndef HAVE_MEMSET_EXPLICIT |
1135 | | void *rep_memset_explicit(void *block, int c, size_t size) |
1136 | 5.69M | { |
1137 | 5.69M | void *ptr = memset(block, c, size); |
1138 | 5.69M | #ifdef HAVE_GCC_VOLATILE_MEMORY_PROTECTION |
1139 | | /* See http://llvm.org/bugs/show_bug.cgi?id=15495 */ |
1140 | 5.69M | __asm__ volatile("" : : "g"(block) : "memory"); |
1141 | 5.69M | #endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */ |
1142 | | |
1143 | 5.69M | return ptr; |
1144 | 5.69M | } |
1145 | | #endif |
1146 | | |
1147 | | #ifndef HAVE_GETPROGNAME |
1148 | | # ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME |
1149 | | # define PROGNAME_SIZE 32 |
1150 | | static char rep_progname[PROGNAME_SIZE]; |
1151 | | # endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */ |
1152 | | |
1153 | | const char *rep_getprogname(void) |
1154 | 0 | { |
1155 | 0 | #ifdef HAVE_PROGRAM_INVOCATION_SHORT_NAME |
1156 | 0 | return program_invocation_short_name; |
1157 | | #else /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */ |
1158 | | FILE *fp = NULL; |
1159 | | char cmdline[4096] = {0}; |
1160 | | char *p = NULL; |
1161 | | pid_t pid; |
1162 | | size_t nread; |
1163 | | int len; |
1164 | | int rc; |
1165 | | |
1166 | | if (rep_progname[0] != '\0') { |
1167 | | return rep_progname; |
1168 | | } |
1169 | | |
1170 | | len = snprintf(rep_progname, sizeof(rep_progname), "%s", "<unknown>"); |
1171 | | if (len <= 0) { |
1172 | | return NULL; |
1173 | | } |
1174 | | |
1175 | | pid = getpid(); |
1176 | | if (pid <= 1 || pid == (pid_t)-1) { |
1177 | | return NULL; |
1178 | | } |
1179 | | |
1180 | | len = snprintf(cmdline, |
1181 | | sizeof(cmdline), |
1182 | | "/proc/%u/cmdline", |
1183 | | (unsigned int)pid); |
1184 | | if (len <= 0 || len == sizeof(cmdline)) { |
1185 | | return NULL; |
1186 | | } |
1187 | | |
1188 | | fp = fopen(cmdline, "r"); |
1189 | | if (fp == NULL) { |
1190 | | return NULL; |
1191 | | } |
1192 | | |
1193 | | nread = fread(cmdline, 1, sizeof(cmdline) - 1, fp); |
1194 | | |
1195 | | rc = fclose(fp); |
1196 | | if (rc != 0) { |
1197 | | return NULL; |
1198 | | } |
1199 | | |
1200 | | if (nread == 0) { |
1201 | | return NULL; |
1202 | | } |
1203 | | |
1204 | | cmdline[nread] = '\0'; |
1205 | | |
1206 | | p = strrchr(cmdline, '/'); |
1207 | | if (p != NULL) { |
1208 | | p++; |
1209 | | } else { |
1210 | | p = cmdline; |
1211 | | } |
1212 | | |
1213 | | len = strlen(p); |
1214 | | if (len > PROGNAME_SIZE) { |
1215 | | p[PROGNAME_SIZE - 1] = '\0'; |
1216 | | } |
1217 | | |
1218 | | (void)snprintf(rep_progname, sizeof(rep_progname), "%s", p); |
1219 | | |
1220 | | return rep_progname; |
1221 | | #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */ |
1222 | 0 | } |
1223 | | #endif /* HAVE_GETPROGNAME */ |
1224 | | |
1225 | | #ifndef HAVE_COPY_FILE_RANGE |
1226 | | ssize_t rep_copy_file_range(int fd_in, |
1227 | | loff_t *off_in, |
1228 | | int fd_out, |
1229 | | loff_t *off_out, |
1230 | | size_t len, |
1231 | | unsigned int flags) |
1232 | | { |
1233 | | # ifdef HAVE_SYSCALL_COPY_FILE_RANGE |
1234 | | return syscall(__NR_copy_file_range, |
1235 | | fd_in, |
1236 | | off_in, |
1237 | | fd_out, |
1238 | | off_out, |
1239 | | len, |
1240 | | flags); |
1241 | | # endif /* HAVE_SYSCALL_COPY_FILE_RANGE */ |
1242 | | errno = ENOSYS; |
1243 | | return -1; |
1244 | | } |
1245 | | #endif /* HAVE_COPY_FILE_RANGE */ |
1246 | | |
1247 | | #ifdef HAVE_LINUX_IOCTL |
1248 | | # include <linux/fs.h> |
1249 | | # include <sys/ioctl.h> |
1250 | | #endif |
1251 | | |
1252 | | ssize_t rep_copy_reflink(int src_fd, |
1253 | | off_t src_off, |
1254 | | int dst_fd, |
1255 | | off_t dst_off, |
1256 | | off_t to_copy) |
1257 | 0 | { |
1258 | 0 | #ifdef HAVE_LINUX_IOCTL |
1259 | 0 | struct file_clone_range cr; |
1260 | |
|
1261 | 0 | cr = (struct file_clone_range) { |
1262 | 0 | .src_fd = src_fd, |
1263 | 0 | .src_offset = (uint64_t)src_off, |
1264 | 0 | .dest_offset = (uint64_t)dst_off, |
1265 | 0 | .src_length = (uint64_t)to_copy, |
1266 | 0 | }; |
1267 | |
|
1268 | 0 | return ioctl(dst_fd, FICLONERANGE, &cr); |
1269 | | #else |
1270 | | errno = ENOSYS; |
1271 | | return -1; |
1272 | | #endif |
1273 | 0 | } |
1274 | | |
1275 | | #ifndef HAVE_OPENAT2 |
1276 | | |
1277 | | /* fallback known wellknown __NR_openat2 values */ |
1278 | | #ifndef __NR_openat2 |
1279 | | # if defined(LINUX) && defined(HAVE_SYS_SYSCALL_H) |
1280 | | # if defined(__i386__) |
1281 | | # define __NR_openat2 437 |
1282 | | # elif defined(__x86_64__) && defined(__LP64__) |
1283 | 0 | # define __NR_openat2 437 /* 437 0x1B5 */ |
1284 | | # elif defined(__x86_64__) && defined(__ILP32__) |
1285 | | # define __NR_openat2 1073742261 /* 1073742261 0x400001B5 */ |
1286 | | # elif defined(__aarch64__) |
1287 | | # define __NR_openat2 437 |
1288 | | # elif defined(__arm__) |
1289 | | # define __NR_openat2 437 |
1290 | | # elif defined(__sparc__) |
1291 | | # define __NR_openat2 437 |
1292 | | # endif |
1293 | | # endif /* defined(LINUX) && defined(HAVE_SYS_SYSCALL_H) */ |
1294 | | #endif /* !__NR_openat2 */ |
1295 | | |
1296 | | #ifdef DISABLE_OPATH |
1297 | | /* |
1298 | | * systems without O_PATH also don't have openat2, |
1299 | | * so make sure we at a realistic combination. |
1300 | | */ |
1301 | | #undef __NR_openat2 |
1302 | | #endif /* DISABLE_OPATH */ |
1303 | | |
1304 | | long rep_openat2(int dirfd, const char *pathname, |
1305 | | struct open_how *how, size_t size) |
1306 | 0 | { |
1307 | 0 | #ifdef __NR_openat2 |
1308 | | #if _FILE_OFFSET_BITS == 64 && SIZE_MAX == 0xffffffffUL && defined(O_LARGEFILE) |
1309 | | struct open_how __how; |
1310 | | |
1311 | | #if defined(O_PATH) && ! defined(DISABLE_OPATH) |
1312 | | if ((how->flags & O_PATH) == 0) |
1313 | | #endif |
1314 | | { |
1315 | | if (sizeof(__how) == size) { |
1316 | | __how = *how; |
1317 | | |
1318 | | __how.flags |= O_LARGEFILE; |
1319 | | how = &__how; |
1320 | | } |
1321 | | } |
1322 | | #endif |
1323 | |
|
1324 | 0 | return syscall(__NR_openat2, |
1325 | 0 | dirfd, |
1326 | 0 | pathname, |
1327 | 0 | how, |
1328 | 0 | size); |
1329 | | #else |
1330 | | errno = ENOSYS; |
1331 | | return -1; |
1332 | | #endif |
1333 | 0 | } |
1334 | | #endif /* !HAVE_OPENAT2 */ |
1335 | | |
1336 | | #ifndef HAVE_RENAMEAT2 |
1337 | | |
1338 | | /* fallback to wellknown __NR_renameat2 values */ |
1339 | | #ifndef __NR_renameat2 |
1340 | | # if defined(LINUX) && defined(HAVE_SYS_SYSCALL_H) |
1341 | | # if defined(__i386__) |
1342 | | # define __NR_renameat2 353 |
1343 | | # elif defined(__x86_64__) && defined(__LP64__) |
1344 | | # define __NR_renameat2 316 /* 316 0x13C */ |
1345 | | # elif defined(__x86_64__) && defined(__ILP32__) |
1346 | | # define __NR_renameat2 1073742140 /* 1073742140 0x4000013C */ |
1347 | | # elif defined(__aarch64__) |
1348 | | # define __NR_renameat2 276 |
1349 | | # elif defined(__arm__) |
1350 | | # define __NR_renameat2 382 |
1351 | | # elif defined(__sparc__) |
1352 | | # define __NR_renameat2 345 |
1353 | | # endif |
1354 | | # endif /* defined(LINUX) && defined(HAVE_SYS_SYSCALL_H) */ |
1355 | | #endif /* !__NR_renameat2 */ |
1356 | | |
1357 | | #ifdef DISABLE_OPATH |
1358 | | /* |
1359 | | * systems without O_PATH also don't have renameat2, |
1360 | | * so make sure we at a realistic combination. |
1361 | | */ |
1362 | | #undef __NR_renameat2 |
1363 | | #endif /* DISABLE_OPATH */ |
1364 | | |
1365 | | int rep_renameat2(int __oldfd, const char *__old, int __newfd, |
1366 | | const char *__new, unsigned int __flags) |
1367 | | { |
1368 | | if (__flags != 0) { |
1369 | | #ifdef __NR_renameat2 |
1370 | | int ret; |
1371 | | |
1372 | | ret = syscall(__NR_renameat2, |
1373 | | __oldfd, |
1374 | | __old, |
1375 | | __newfd, |
1376 | | __new, |
1377 | | __flags); |
1378 | | if (ret != -1 || errno != ENOSYS) { |
1379 | | /* |
1380 | | * if it's ENOSYS, we fallback |
1381 | | * to EINVAL below, otherwise |
1382 | | * we return what the kernel |
1383 | | * did. |
1384 | | */ |
1385 | | return ret; |
1386 | | } |
1387 | | #endif |
1388 | | errno = EINVAL; |
1389 | | return -1; |
1390 | | } |
1391 | | |
1392 | | return renameat(__oldfd, __old, __newfd, __new); |
1393 | | } |
1394 | | #endif /* ! HAVE_RENAMEAT2 */ |
1395 | | |
1396 | | const char hexchars_lower[] = "0123456789abcdef"; |
1397 | | const char hexchars_upper[] = "0123456789ABCDEF"; |