2012-12-03 23:42:35 +00:00
|
|
|
/*
|
|
|
|
Serval DNA native Operating System interface
|
|
|
|
Copyright (C) 2012 Serval Project Inc.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2013-12-04 06:44:14 +00:00
|
|
|
#ifndef __SERVAL_DNA__OS_H
|
|
|
|
#define __SERVAL_DNA__OS_H
|
2013-02-25 04:53:03 +00:00
|
|
|
|
2014-05-23 08:19:00 +00:00
|
|
|
#include <sys/types.h> // for off64_t
|
|
|
|
#include <stdio.h> // for NULL
|
2012-12-03 23:42:35 +00:00
|
|
|
#include <stdlib.h>
|
2014-05-23 08:19:00 +00:00
|
|
|
#include <stdint.h> // for int64_t
|
|
|
|
#include <unistd.h> // for lseek()
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
#include <strings.h> // for bcopy()
|
|
|
|
#endif
|
|
|
|
#include <string.h> // for memcmp()
|
2014-03-07 06:25:38 +00:00
|
|
|
#include "log.h"
|
2012-12-03 23:42:35 +00:00
|
|
|
|
2013-12-04 06:44:14 +00:00
|
|
|
#ifndef __SERVAL_DNA__OS_INLINE
|
2013-02-25 04:53:03 +00:00
|
|
|
# if __GNUC__ && !__GNUC_STDC_INLINE__
|
2013-12-04 06:44:14 +00:00
|
|
|
# define __SERVAL_DNA__OS_INLINE extern inline
|
2013-02-25 04:53:03 +00:00
|
|
|
# else
|
2013-12-04 06:44:14 +00:00
|
|
|
# define __SERVAL_DNA__OS_INLINE inline
|
2013-02-25 04:53:03 +00:00
|
|
|
# endif
|
|
|
|
#endif
|
2012-12-03 23:42:35 +00:00
|
|
|
|
|
|
|
/* All wall clock times in the Serval daemon are represented in milliseconds
|
|
|
|
* since the Unix epoch. The gettime_ms() function uses gettimeofday(2) to
|
|
|
|
* return this value when called. The time_ms_t typedef should be used
|
|
|
|
* wherever this time value is handled or stored.
|
|
|
|
*
|
|
|
|
* This type could perfectly well be unsigned, but is defined as signed to
|
|
|
|
* avoid the need to cast or define a special signed timedelta_ms_t type at **
|
|
|
|
* (1):
|
|
|
|
*
|
|
|
|
* static time_ms_t then = 0;
|
|
|
|
* time_ms_t now = gettime_ms();
|
|
|
|
* time_ms_t ago = now - then; // ** (1)
|
|
|
|
* if (then && ago < 0) {
|
|
|
|
* ... time going backwards ...
|
|
|
|
* } else {
|
|
|
|
* ... time has advanced ...
|
|
|
|
* then = now;
|
|
|
|
* }
|
|
|
|
*/
|
2013-10-06 19:24:46 +00:00
|
|
|
typedef int64_t time_ms_t;
|
Refactor manifest: specific setter functions
Replace generic rhizome_manifest_set() and rhizome_manifest_set_ll()
with per-field setter functions, eg, rhizome_manifest_set_filesize().
Struct rhizome_manifest elements for all known fields, to replace the
use of rhizome_manifest_get() and rhizome_manifest_get_ll() everywhere:
sender, recipient, service, name, date, bundle_key.
Add boolean validity flags for binary blob types, to avoid having to compare
with many bytes of all-zero to detect presence, eg, has_sender, has_recipient,
has_author, has_bundle_key. These maintained by the setter functions.
Rename existing manifest struct elements to be the same as their field
names: fileLength -> filesize, journalTail -> tail.
More use of unsigned int, size_t and uint64_t for payload sizes, offsets, byte
counts, etc. especially in rhizome_store.c and meshms.c. More uniform use of
size_t to dimension memory buffers. Fix some printf(3) style format strings
for 64-bit correctness on 32-bit systems. Use new constant RHIZOME_SIZE_UNSET
instead of -1 to indicate unknown dimension, and explicitly assert its absence
before comparisons and arithmetic, for safety.
Replace some 'int' loop variables with 'unsigned' where appropriate.
Fix bugs discovered in MeshMS bundle private/public key generation and
bundle secret key handling for export/extract commands.
Instrument the first MeshMS test case to aid debugging.
New debug config flag: debug.manifest logs all modifications to all manifest
fields by setter functions.
Rename debug config flag: debug.rhizome_bind -> debug.rhizome_sql_bind.
2013-10-30 12:52:19 +00:00
|
|
|
#define PRItime_ms_t PRId64
|
2014-05-07 01:41:04 +00:00
|
|
|
#define TIME_MS_NEVER_WILL INT64_MAX
|
|
|
|
#define TIME_MS_NEVER_HAS INT64_MIN
|
2012-12-03 23:42:35 +00:00
|
|
|
|
|
|
|
time_ms_t gettime_ms();
|
|
|
|
time_ms_t sleep_ms(time_ms_t milliseconds);
|
2014-05-07 05:32:51 +00:00
|
|
|
struct timeval time_ms_to_timeval(time_ms_t);
|
2012-12-03 23:42:35 +00:00
|
|
|
|
2013-02-25 04:53:03 +00:00
|
|
|
#ifndef HAVE_BZERO
|
2013-12-04 06:44:14 +00:00
|
|
|
__SERVAL_DNA__OS_INLINE void bzero(void *buf, size_t len) {
|
2013-02-25 04:53:03 +00:00
|
|
|
memset(buf, 0, len);
|
|
|
|
}
|
|
|
|
#endif
|
2012-12-03 23:42:35 +00:00
|
|
|
|
2013-02-25 04:53:03 +00:00
|
|
|
#ifndef HAVE_BCOPY
|
2013-12-04 06:44:14 +00:00
|
|
|
__SERVAL_DNA__OS_INLINE void bcopy(const void *src, void *dst, size_t len) {
|
2013-02-25 04:53:03 +00:00
|
|
|
memcpy(dst, src, len);
|
|
|
|
}
|
|
|
|
#endif
|
2012-12-03 23:42:35 +00:00
|
|
|
|
2013-05-17 04:29:42 +00:00
|
|
|
#ifndef HAVE_BCMP
|
2013-12-04 06:44:14 +00:00
|
|
|
__SERVAL_DNA__OS_INLINE int bcmp(const void *s1, const void *s2, size_t n) {
|
2013-05-21 03:15:33 +00:00
|
|
|
// bcmp() is only an equality test, not an order test, so its return value
|
|
|
|
// is not specified as negative or positive, only non-zero. Hoewver
|
|
|
|
// memcmp() is an order test. We deliberately discard negative return
|
|
|
|
// values from memcmp(), to avoid misleading developers into assuming that
|
|
|
|
// bcmp() is an ordering operator and writing code that depends on that,
|
|
|
|
// which of course would fail on platforms with a native bcmp() function.
|
|
|
|
return memcmp(s1, s2, n) != 0;
|
2013-05-17 04:29:42 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-02-17 04:03:32 +00:00
|
|
|
/* If there is no lseek64(2) system call but off_t is 64 bits, then we can use
|
|
|
|
* lseek(2) instead.
|
|
|
|
*/
|
|
|
|
#ifndef HAVE_LSEEK64
|
|
|
|
# if SIZEOF_OFF_T != 8
|
|
|
|
# error "lseek64(2) system call is not available and `sizeof(off_t) is not 8"
|
|
|
|
# endif
|
|
|
|
# ifndef HAVE_OFF64_T
|
2014-02-17 04:44:14 +00:00
|
|
|
typedef off_t off64_t;
|
2014-02-17 04:03:32 +00:00
|
|
|
__SERVAL_DNA__OS_INLINE off64_t lseek64(int fd, off64_t offset, int whence) {
|
|
|
|
return lseek(fd, offset, whence);
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2013-04-04 07:07:49 +00:00
|
|
|
/* The "e" variants log the error before returning -1.
|
|
|
|
*/
|
2014-03-26 05:05:43 +00:00
|
|
|
typedef void MKDIR_LOG_FUNC(struct __sourceloc, const char *, mode_t);
|
|
|
|
MKDIR_LOG_FUNC log_info_mkdir;
|
|
|
|
int _mkdirs(struct __sourceloc, const char *path, mode_t mode, MKDIR_LOG_FUNC *);
|
|
|
|
int _mkdirsn(struct __sourceloc, const char *path, size_t len, mode_t mode, MKDIR_LOG_FUNC *);
|
|
|
|
int _emkdirs(struct __sourceloc, const char *path, mode_t mode, MKDIR_LOG_FUNC *);
|
|
|
|
int _emkdirsn(struct __sourceloc, const char *path, size_t len, mode_t mode, MKDIR_LOG_FUNC *);
|
2014-03-07 06:25:38 +00:00
|
|
|
|
2014-03-26 05:05:43 +00:00
|
|
|
#define mkdirs_log(path, mode, func) _mkdirs(__WHENCE__, (path), (mode), (func))
|
|
|
|
#define mkdirsn_log(path, len, mode, func) _mkdirsn(__WHENCE__, (path), (len), (mode), (func))
|
|
|
|
#define emkdirs_log(path, mode, func) _emkdirs(__WHENCE__, (path), (mode), (func))
|
|
|
|
#define emkdirsn_log(path, len, mode, func) _emkdirsn(__WHENCE__, (path), (len), (mode), (func))
|
|
|
|
|
|
|
|
#define mkdirs(path, mode) mkdirs_log((path), (mode), NULL)
|
|
|
|
#define mkdirsn(path, len, mode) mkdirsn_log((path), (len), (mode), NULL)
|
|
|
|
#define emkdirs(path, mode) emkdirs_log((path), (mode), NULL)
|
|
|
|
#define emkdirsn(path, len, mode) emkdirsn_log((path), (len), (mode), NULL)
|
|
|
|
|
|
|
|
#define mkdirs_info(path, mode) mkdirs_log((path), (mode), log_info_mkdir)
|
|
|
|
#define mkdirsn_info(path, len, mode) mkdirsn_log((path), (len), (mode), log_info_mkdir)
|
|
|
|
#define emkdirs_info(path, mode) emkdirs_log((path), (mode), log_info_mkdir)
|
|
|
|
#define emkdirsn_info(path, len, mode) emkdirsn_log((path), (len), (mode), log_info_mkdir)
|
2012-12-03 23:42:35 +00:00
|
|
|
|
|
|
|
void srandomdev();
|
2013-10-06 18:15:49 +00:00
|
|
|
int urandombytes(unsigned char *buf, size_t len);
|
2012-12-03 23:42:35 +00:00
|
|
|
|
2013-02-25 04:55:53 +00:00
|
|
|
/* Read the symbolic link into the supplied buffer and add a terminating nul.
|
|
|
|
* Logs an ERROR and returns -1 if the buffer is too short to hold the link
|
|
|
|
* content and the terminating nul. If readlink(2) returns an error, then logs
|
|
|
|
* an ERROR and returns -1. Otherwise, returns the number of bytes read,
|
|
|
|
* including the terminating nul, ie, returns what readlink(2) returns plus
|
2014-05-05 08:42:25 +00:00
|
|
|
* one. If the 'len' argument is given as zero, then ignores 'buf' and returns
|
|
|
|
* the number of bytes that would be read, by calling lstat(2) instead of
|
|
|
|
* readlink(2), plus one for the terminating nul. Beware of the following race
|
|
|
|
* condition: a symbolic link may be altered between calling the lstat(2) and
|
|
|
|
* readlink(2), so the following apparently overflow-proof code may still fail
|
|
|
|
* from a buffer overflow in the second call to read_symlink():
|
2013-02-25 04:55:53 +00:00
|
|
|
*
|
|
|
|
* char *readlink_malloc(const char *path) {
|
|
|
|
* ssize_t len = read_symlink(path, NULL, 0);
|
|
|
|
* if (len == -1)
|
|
|
|
* return NULL;
|
|
|
|
* char *buf = malloc(len);
|
|
|
|
* if (buf == NULL)
|
|
|
|
* return NULL;
|
|
|
|
* if (read_symlink(path, buf, len) == -1) {
|
|
|
|
* free(buf);
|
|
|
|
* return NULL;
|
|
|
|
* }
|
|
|
|
* return buf;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* @author Andrew Bettison <andrew@servalproject.com>
|
|
|
|
*/
|
|
|
|
ssize_t read_symlink(const char *path, char *buf, size_t len);
|
|
|
|
|
2013-12-19 08:27:12 +00:00
|
|
|
/* Read the whole file into the given buffer. If the file will not fit into
|
|
|
|
* the buffer or if there is an error opening or reading the file, logs an
|
|
|
|
* error and returns -1. Otherwise, returns the number of bytes read.
|
|
|
|
*
|
|
|
|
* @author Andrew Bettison <andrew@servalproject.com>
|
|
|
|
*/
|
|
|
|
ssize_t read_whole_file(const char *path, unsigned char *buffer, size_t buffer_size);
|
|
|
|
|
2014-04-29 03:06:58 +00:00
|
|
|
/* Read the whole file into a buffer. If *bufp is NULL then uses malloc(3) to
|
|
|
|
* create a buffer first, the size of the file (up to a maximum of *sizp if
|
|
|
|
* *sizp is not zero), and assigns the address to *bufp. If the file will not
|
|
|
|
* fit into the buffer or if there is an error from malloc(3) or opening or
|
|
|
|
* reading the file, logs an error and returns -1. Otherwise, returns 0.
|
|
|
|
*
|
|
|
|
* @author Andrew Bettison <andrew@servalproject.com>
|
|
|
|
*/
|
|
|
|
int malloc_read_whole_file(const char *path, unsigned char **bufp, size_t *sizp);
|
|
|
|
|
2014-04-29 05:34:20 +00:00
|
|
|
/* File metadata primitives, used for detecting when a file has changed.
|
|
|
|
*
|
|
|
|
* @author Andrew Bettison <andrew@servalproject.com>
|
|
|
|
*/
|
|
|
|
struct file_meta {
|
|
|
|
struct timespec mtime;
|
|
|
|
off_t size;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define FILE_META_UNKNOWN ((struct file_meta){ .mtime = { .tv_sec = -1, .tv_nsec = -1 }, .size = -1 })
|
|
|
|
|
|
|
|
// A non-existent file is treated as size == 0 and an impossible modification
|
|
|
|
// time, so that cmp_file_meta() will not compare it as equal with any existing
|
|
|
|
// file.
|
|
|
|
#define FILE_META_NONEXIST ((struct file_meta){ .mtime = { .tv_sec = -1, .tv_nsec = -1 }, .size = 0 })
|
|
|
|
|
|
|
|
__SERVAL_DNA__OS_INLINE int is_file_meta_nonexist(const struct file_meta *m) {
|
|
|
|
return m->mtime.tv_sec == -1 && m->mtime.tv_nsec == -1 && m->size == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_file_meta(const char *path, struct file_meta *metap);
|
|
|
|
int cmp_file_meta(const struct file_meta *a, const struct file_meta *b);
|
|
|
|
|
|
|
|
// Ensure that the metadata of a file differs from a given original metadata,
|
|
|
|
// by bumping the file's modification time or altering its inode.
|
|
|
|
int alter_file_meta(const char *path, const struct file_meta *origp, struct file_meta *metap);
|
|
|
|
|
2014-05-05 08:42:01 +00:00
|
|
|
/* Fill the given buffer with the nul-terminated absolute path of the calling
|
|
|
|
* process's executable. Logs an error and returns -1 if the executable cannot
|
|
|
|
* be determined or the supplied buffer is too short. Otherwise returns the
|
|
|
|
* number of bytes placed in the buffer, including the terminating nul (ie,
|
|
|
|
* returns strlen(buf) + 1).
|
|
|
|
*
|
|
|
|
* @author Andrew Bettison <andrew@servalproject.com>
|
|
|
|
*/
|
|
|
|
ssize_t get_self_executable_path(char *buf, size_t len);
|
|
|
|
|
2013-12-04 06:44:14 +00:00
|
|
|
#endif //__SERVAL_DNA__OS_H
|
2014-05-05 08:42:01 +00:00
|
|
|
|