#include #include #include #include #include #include #include #include #include "sys.h" String shell_exec(String cmd) { printf("(i) shell_exec(%s)\n", cmd.c_str()); String data; FILE * stream; const int max_buffer = 256; char buffer[max_buffer]; cmd.append(" 2>&1"); stream = popen(cmd.c_str(), "r"); if (stream) { while (!feof(stream)) if (fgets(buffer, max_buffer, stream) != NULL) data.append(buffer); pclose(stream); } return data; } String shell_escape(String raw) { // FIXME return("\"" + raw + "\""); /* ` U+0060 (Grave Accent) Backtick Command substitution ~ U+007E Tilde Tilde expansion ! U+0021 Exclamation mark History expansion # U+0023 Number sign Hash Comments $ U+0024 Dollar sign Parameter expansion & U+0026 Ampersand Background commands * U+002A Asterisk Filename expansion and globbing ( U+0028 Left Parenthesis Subshells ) U+0029 Right Parenthesis Subshells U+0009 Tab (⇥) Word splitting (whitespace) { U+007B Left Curly Bracket Left brace Brace expansion [ U+005B Left Square Bracket Filename expansion and globbing | U+007C Vertical Line Vertical bar Pipelines \ U+005C Reverse Solidus Backslash Escape character ; U+003B Semicolon Separating commands ' U+0027 Apostrophe Single quote String quoting " U+0022 Quotation Mark Double quote String quoting with interpolation ↩ U+000A Line Feed Newline Line break < U+003C Less than Input redirection > U+003E Greater than Output redirection ? U+003F Question mark Filename expansion and globbing   U+0020 Space Word splitting1 (whitespace) */ } String basename(String fn) { String result; while(fn.length() > 0) result = nibble("/", fn); //printf("basename(%s) %s\n", fn.c_str(), result.c_str()); return(result); } String dirname(String fn) { String result; auto seg = split(fn, "/"); seg.pop_back(); result = join(seg, "/"); //printf("dirname(%s) %s seg#%i\n", fn.c_str(), result.c_str(), seg.size()); return(result); } bool mkdir(String path) { shell_exec(String("mkdir -p ")+" "+shell_escape(path)); return(true); } bool file_exists(String path) { std::filesystem::path fp{ path }; return(std::filesystem::exists(fp)); } String file_get_contents(String file_name) { try { std::ifstream ifs(file_name); String content( (std::istreambuf_iterator(ifs) ), (std::istreambuf_iterator() ) ); return(content); } catch(std::exception e) { return(""); } } bool file_put_contents(String file_name, String content) { try { std::ofstream out(file_name); out << content; out.close(); return(true); } catch(std::exception e) { return(false); } } String get_cwd() { return(std::filesystem::current_path()); } void set_cwd(String path) { chdir(path.c_str()); } time_t file_mtime(String file_name) { struct stat info; if (stat(file_name.c_str(), &info) != 0) { return(0); } else { return(info.st_mtime); } } void unlink(String file_name) { remove(file_name.c_str()); } String expand_path(String path) { String result; auto base_path = split(get_cwd(), "/"); auto rel_path = split(path, "/"); for(auto& s : rel_path) { if(s == "..") { base_path.pop_back(); } else if(s == ".") { } else { base_path.push_back(s); } } return(join(base_path, "/")); } f64 microtime() { return ((f64)std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch()).count()) / 1000000; } u64 time() { return(std::time(0)); } String date(String format, u64 timestamp) { String ts; String fmt; if(timestamp > 0) ts = String("-d '@")+std::to_string(timestamp)+"'"; if(format != "") fmt = String("+'"+format+"'"); return(trim(shell_exec("date "+ts+" "+fmt))); } String gmdate(String format, u64 timestamp) { String ts; String fmt; if(timestamp > 0) ts = String("-d '@")+std::to_string(timestamp)+"'"; if(format == "RFC1123") format = "%a, %d %b %Y %T GMT"; if(format != "") fmt = String("+'"+format+"'"); return(trim(shell_exec("date -u "+ts+" "+fmt))); } u64 parse_time(String time_String) { return(int_val(trim(shell_exec("date -u -d '"+time_String+"' +'%s'")))); } u64 socket_connect(String host, short port) { /*String addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; String sockaddr *ai_addr; char *ai_canonname; String addrinfo *ai_next; };*/ auto sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(sockfd < 0) { echo("SOCKET ERROR (could not open socket)\n"); perror("SOCKET ERROR "); return(0); } struct sockaddr_in addr = {0}; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(host.c_str()); if(connect(sockfd, (struct sockaddr*) &addr, sizeof(addr)) < 0) { echo("SOCKET ERROR (could not connect to address " + String(host) + ":" + std::to_string(port) + ")\n"); perror("SOCKET ERROR "); return(0); } context->resources.sockets.push_back(sockfd); return(sockfd); } void socket_close(u64 sockfd) { close(sockfd); } bool socket_write(u64 sockfd, String data) { return(write(sockfd, data.c_str(), data.length()) >= 0); } String socket_read(u64 sockfd, u32 max_length, u32 timeout) { struct timeval tv; tv.tv_sec = timeout; tv.tv_usec = 0; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv); char buf[max_length+1]; auto byte_count = recv(sockfd, buf, sizeof(buf), 0); if(byte_count > 0) { buf[byte_count] = 0; String result(buf, byte_count+1); return(result); } return(""); } String memcache_escape_key(String key) { String result; for(auto c : key) { if(isspace(c)) c = '_'; result.append(1, c); } return(result); } StringList memcache_escape_keys(StringList keys) { StringList result; for(auto s : keys) { result.push_back(memcache_escape_key(s)); } return(result); } u64 memcache_connect(String host, short port) { return(socket_connect(host, port)); } String memcache_command(u64 connection, String command) { socket_write(connection, command+"\r\n"); return(socket_read(connection)); // FIXME: do multi-chunk until END line is received! } bool memcache_set(u64 connection, String key, String value, u64 expires_in) { socket_write(connection, // set KEY META_DATA EXPIRY_TIME LENGTH_IN_BYTES String("set ") + memcache_escape_key(key) + " 0 " + std::to_string(expires_in) + " " + std::to_string(value.length()) + "\r\n" + value + "\r\n"); return("STORED" == trim(socket_read(connection))); } bool memcache_delete(u64 connection, String key) { socket_write(connection, // set KEY META_DATA EXPIRY_TIME LENGTH_IN_BYTES String("delete ") + memcache_escape_key(key) + "\r\n" ); return("DELETED" == trim(socket_read(connection))); } String memcache_get(u64 connection, String key, String default_value) { auto res = memcache_command(connection, String("get ")+memcache_escape_key(key)); String t = nibble(res, " "); if(t == "VALUE") { String key = nibble(res, " "); String meta = nibble(res, " "); u32 length = stoi(nibble(res, "\r\n")); return(res.substr(0, length)); } return(default_value); } StringMap memcache_get_multiple(u64 connection, StringList keys) { StringMap result; // to do: escape key String auto res = memcache_command(connection, String("get ")+join(memcache_escape_keys(keys), " ")); while(res.length() > 0) { String t = nibble(res, " "); if(t == "VALUE") { String key = nibble(res, " "); String meta = nibble(res, " "); u32 length = stoi(nibble(res, "\r\n")); result[key] = res.substr(0, length); res = res.substr(length+2); } } return(result); } void on_segfault(int sig) { void *array[10]; size_t size; // get void*'s for all entries on the stack size = backtrace(array, 10); // print out all the frames to stderr fprintf(stderr, "SEG FAULT: %d:\n", sig); backtrace_symbols_fd(array, size, STDERR_FILENO); exit(1); } struct Worker { pid_t pid; }; std::map workers; #include #include #include void spawn_subprocess(std::function exec_after_spawn) { parent_pid = getpid(); pid_t p; p = fork(); if(p == 0) { my_pid = getpid(); //printf("(C) child procress started, PID:%i\n", my_pid); prctl(PR_SET_PDEATHSIG, SIGHUP); exec_after_spawn(); } else { Worker w; w.pid = p; workers[w.pid] = w; printf("(P) child procress spawned: PID %i\n", p); } } void on_child_exit(int sig) { pid_t pid; int status; if ((pid = waitpid(-1, &status, WNOHANG)) != -1) { if(workers.count(pid) > 0) { workers.erase(pid); printf("(P) child terminated (PID:%i)\n", pid); //spawn_subprocess(); } } }