2 Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
17 * Netatalk utility functions
22 #endif /* HAVE_CONFIG_H */
29 #include <sys/types.h>
36 #include <atalk/adouble.h>
38 #include <atalk/afp.h>
39 #include <atalk/logger.h>
40 #include <atalk/vfs.h>
41 #include <atalk/util.h>
42 #include <atalk/unix.h>
44 /* close all FDs >= a specified value */
45 static void closeall(int fd)
47 int fdlimit = sysconf(_SC_OPEN_MAX);
56 * Fork, exit parent, setsid(), optionally chdir("/"), optionally close all fds
58 * returns -1 on failure, but you can't do much except exit in that case
59 * since we may already have forked
61 int daemonize(int nochdir, int noclose)
89 open("/dev/null",O_RDWR);
97 static uid_t saved_uid = -1;
99 void become_root(void)
101 saved_uid = geteuid();
103 AFP_PANIC("Can't seteuid(0)");
106 void unbecome_root(void)
108 if (saved_uid == -1 || seteuid(saved_uid) < 0)
109 AFP_PANIC("Can't seteuid back");
114 * @brief get cwd in static buffer
116 * @returns pointer to path or pointer to error messages on error
118 const char *getcwdpath(void)
120 static char cwd[MAXPATHLEN + 1];
123 if ((p = getcwd(cwd, MAXPATHLEN)) != NULL)
126 return strerror(errno);
130 * @brief Request absolute path
132 * @returns Absolute filesystem path to object
134 const char *fullpathname(const char *name)
136 static char wd[MAXPATHLEN + 1];
141 if (getcwd(wd , MAXPATHLEN)) {
142 strlcat(wd, "/", MAXPATHLEN);
143 strlcat(wd, name, MAXPATHLEN);
145 strlcpy(wd, name, MAXPATHLEN);
152 * Takes a buffer with a path, strips slashs, returns basename
156 * "[/][dir/[...]]file"
158 * "[/][dir/[...]]dir/[/]"
159 * Result is "file" or "dir"
161 * @returns pointer to basename in path buffer, buffer is possibly modified
163 char *stripped_slashes_basename(char *p)
165 int i = strlen(p) - 1;
166 while (i > 0 && p[i] == '/')
168 return (strrchr(p, '/') ? strrchr(p, '/') + 1 : p);
171 /*********************************************************************************
172 * chdir(), chmod(), chown(), stat() wrappers taking an additional option.
173 * Currently the only used options are O_NOFOLLOW, used to switch between symlink
174 * behaviour, and O_NETATALK_ACL for ochmod() indicating chmod_acl() shall be
175 * called which does special ACL handling depending on the filesytem
176 *********************************************************************************/
178 int ostat(const char *path, struct stat *buf, int options)
180 if (options & O_NOFOLLOW)
181 return lstat(path, buf);
183 return stat(path, buf);
186 int ochown(const char *path, uid_t owner, gid_t group, int options)
188 if (options & O_NOFOLLOW)
189 return lchown(path, owner, group);
191 return chown(path, owner, group);
195 * chmod() wrapper for symlink and ACL handling
197 * @param path (r) path
198 * @param mode (r) requested mode
199 * @param sb (r) stat() of path or NULL
200 * @param option (r) O_NOFOLLOW | O_NETATALK_ACL
202 * Options description:
203 * O_NOFOLLOW: don't chmod() symlinks, do nothing, return 0
204 * O_NETATALK_ACL: call chmod_acl() instead of chmod()
206 int ochmod(const char *path, mode_t mode, const struct stat *st, int options)
211 if (lstat(path, &sb) != 0)
216 if (options & O_NOFOLLOW)
217 if (S_ISLNK(st->st_mode))
220 if (options & O_NETATALK_ACL) {
221 return chmod_acl(path, mode);
223 return chmod(path, mode);
228 * @brief ostat/fsstatat multiplexer
230 * ostatat mulitplexes ostat and fstatat. If we dont HAVE_ATFUNCS, dirfd is ignored.
232 * @param dirfd (r) Only used if HAVE_ATFUNCS, ignored else, -1 gives AT_FDCWD
233 * @param path (r) pathname
234 * @param st (rw) pointer to struct stat
236 int ostatat(int dirfd, const char *path, struct stat *st, int options)
241 return fstatat(dirfd, path, st, (options & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
243 return ostat(path, st, options);
251 * @brief symlink safe chdir replacement
253 * Only chdirs to dir if it doesn't contain symlinks or if symlink checking
256 * @returns 1 if a path element is a symlink, 0 otherwise, -1 on syserror
258 int ochdir(const char *dir, int options)
260 char buf[MAXPATHLEN+1];
261 char cwd[MAXPATHLEN+1];
265 if (!(options & O_NOFOLLOW))
269 dir is a canonical path (without "../" "./" "//" )
274 if (getcwd(cwd, MAXPATHLEN) == NULL)
282 * chdir request | realpath result | ret
283 * (after getwcwd) | |
284 * =======================================
287 * /a/b/. | /c/d/e/f | 1
289 if (getcwd(buf, MAXPATHLEN) == NULL)
294 /* relative path requested,
297 for (; cwd[i]; i++) {
298 if (buf[i] != cwd[i])
309 for (i = 0; test[i]; i++) {
310 if (test[i] != dir[i]) {
329 * Store n random bytes an buf
331 void randombytes(void *buf, int n)
333 char *p = (char *)buf;
337 if ((fd = open("/dev/urandom", O_RDONLY)) != -1) {
338 /* generate from /dev/urandom */
339 if (read(fd, buf, n) != n) {
344 /* fd now != -1, so srandom wont be called below */
349 gettimeofday(&tv, NULL);
350 srandom((unsigned int)tv.tv_usec);
351 for (i=0 ; i < n ; i++)
352 p[i] = random() & 0xFF;