/**
* mds — A micro-display server
* Copyright © 2014, 2015 Mattias Andrée (maandree@member.fsf.org)
*
* 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 3 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, see .
*/
#ifndef MDS_LIBMDSSERVER_UTIL_H
#define MDS_LIBMDSSERVER_UTIL_H
#include
#include
#include
/**
* Convert a client ID string into a client ID integer
*
* @param str The client ID string
* @return The client ID integer
*/
uint64_t parse_client_id(const char* str);
/**
* Read an environment variable, but handle it as undefined if empty
*
* @param var The environment variable's name
* @return The environment variable's value, `NULL` if empty or not defined
*/
char* getenv_nonempty(const char* var);
/**
* Prepare the server so that it can reexec into
* a newer version of the executed file.
*
* This is required for two reasons:
* 1: We cannot use argv[0] as PATH-resolution may
* cause it to reexec into another pathname, and
* maybe to wrong program. Additionally argv[0]
* may not even refer to the program, and chdir
* could also hinter its use.
* 2: The kernel appends ` (deleted)` to
* `/proc/self/exe` once it has been removed,
* so it cannot be replaced.
*
* The function will should be called immediately, it
* will store the content of `/proc/self/exe`.
*
* @return Zero on success, -1 on error
*/
int prepare_reexec(void);
/**
* Re-exec the server.
* This function only returns on failure.
*
* If `prepare_reexec` failed or has not been called,
* `argv[0]` will be used as a fallback.
*
* @param argc The number of elements in `argv`
* @param argv The command line arguments
* @param reexeced Whether the server has previously been re-exec:ed
*/
void reexec_server(int argc, char** argv, int reexeced);
/**
* Set up a signal trap.
* This function should only be used for common mds
* signals and signals that does not require and
* special settings. This function may choose to add
* additional behaviour depending on the signal, such
* as blocking other signals.
*
* @param signo The signal to trap
* @param function The function to run when the signal is caught
* @return Zero on success, -1 on error
*/
int xsigaction(int signo, void (*function)(int signo));
/**
* Send a message over a socket
*
* @param socket The file descriptor of the socket
* @param message The message to send
* @param length The length of the message
* @return The number of bytes that have been sent (even on error)
*/
size_t send_message(int socket, const char* message, size_t length);
/**
* A version of `atoi` that is strict about the syntax and bounds
*
* @param str The text to parse
* @param value Slot in which to store the value
* @param min The minimum accepted value
* @param max The maximum accepted value
* @return Zero on success, -1 on syntax error
*/
int strict_atoi(const char* str, int* value, int min, int max);
/**
* Send a buffer into a file and ignore interruptions
*
* @param fd The file descriptor
* @param buffer The buffer
* @param length The length of the buffer
* @return Zero on success, -1 on error
*/
int full_write(int fd, const char* buffer, size_t length);
/**
* Read a file completely and ignore interruptions
*
* @param fd The file descriptor
* @param length Output parameter for the length of the file, may be `NULL`
* @return The content of the file, you will need to free it. `NULL` on error
*/
char* full_read(int fd, size_t* length);
/**
* Send a full message even if interrupted
*
* @param socket The file descriptor for the socket to use
* @param message The message to send
* @param length The length of the message
* @return Zero on success, -1 on error
*/
int full_send(int socket, const char* message, size_t length);
/**
* Check whether a string begins with a specific string,
* where neither of the strings are necessarily NUL-terminated
*
* @param haystack The string that should start with the other string
* @param needle The string the first string should start with
* @param haystack_n The length of `haystack`
* @param needle_n The length of `needle`
* @return Whether the `haystack` begins with `needle`
*/
int startswith_n(const char* haystack, const char* needle, size_t haystack_n, size_t needle_n) __attribute__((pure));
/**
* Wrapper around `waitpid` that never returns on an interruption unless
* it is interrupted 100 times within the same second
*
* @param pid See description of `pid` in the documentation for `waitpid`
* @param status See description of `status` in the documentation for `waitpid`
* @param options See description of `options` in the documentation for `waitpid`
* @return See the documentation for `waitpid`
*/
pid_t uninterruptable_waitpid(pid_t pid, int* restrict status, int options);
/**
* Check whether a NUL-terminated string is encoded in UTF-8
*
* @param string The string
* @param allow_modified_nul Whether Modified UTF-8 is allowed, which allows a two-byte encoding for NUL
* @return Zero if good, -1 on encoding error
*/
int verify_utf8(const char* string, int allow_modified_nul) __attribute__((pure));
#endif