static void test_various_read_write_1 (const char *name, unsigned n_entries, TestEntry *entries, uint64_t n_write) { DskError *error = NULL; DskTableFileInterface *iface = &dsk_table_file_interface_trivial; uint64_t big_i; /* index from 0..n_write-1 */ uint32_t small_i; /* index from 0..n_entries-1 */ DskTableFileWriter *writer; DskTableReader *reader; if (cmdline_verbose) fprintf (stderr, "running dataset %s [%llu]\n", name, (unsigned long long) n_write); else fprintf (stderr, "."); writer = iface->new_writer (iface, location, "base", &error); if (writer == NULL) dsk_die ("%s", error->message); for (big_i = small_i = 0; big_i < n_write; big_i++) { TestEntry *e = entries + small_i++; if (small_i == n_entries) small_i = 0; if (!writer->write (writer, strlen (e->key), (uint8_t*) e->key, strlen (e->value), (uint8_t*) e->value, &error)) dsk_die ("error writing: %s", error->message); } if (!writer->close (writer, &error)) dsk_die ("error closing writer: %s", error->message); writer->destroy (writer); reader = iface->new_reader (iface, location, "base", &error); if (reader == NULL) dsk_die ("error creating reader: %s", error->message); small_i = 0; for (big_i = 0; big_i < n_write; big_i++) { TestEntry *e = entries + small_i++; if (small_i == n_entries) small_i = 0; dsk_assert (!reader->at_eof); dsk_assert (reader->key_length == strlen (e->key)); dsk_assert (reader->value_length == strlen (e->value)); dsk_assert (memcmp (reader->key_data, e->key, reader->key_length) == 0); dsk_assert (memcmp (reader->value_data, e->value, reader->value_length) == 0); if (!reader->advance (reader, &error)) dsk_die ("error reading file: %s", error->message); if (big_i + 1 == n_write) break; } dsk_assert (reader->at_eof); reader->destroy (reader); }
int main(int argc, char **argv) { unsigned port = 0; DskHttpServer *server; unsigned i; DskError *error = NULL; dsk_cmdline_init ("snipez server", "Run a snipez server", NULL, 0); dsk_cmdline_add_uint ("port", "Port Number", "PORT", DSK_CMDLINE_MANDATORY, &port); dsk_cmdline_add_uint ("update-period", "Update Period", "MILLIS", 0, &update_period_msecs); dsk_cmdline_add_func ("make-maze", "Make a Maze", "WIDTHxHEIGHT", DSK_CMDLINE_OPTIONAL, handle_make_maze, NULL); dsk_cmdline_add_shortcut ('p', "port"); dsk_cmdline_process_args (&argc, &argv); server = dsk_http_server_new (); for (i = 0; i < DSK_N_ELEMENTS (handlers); i++) { dsk_http_server_match_save (server); dsk_http_server_add_match (server, DSK_HTTP_SERVER_MATCH_PATH, handlers[i].pattern); dsk_http_server_register_cgi_handler (server, (DskHttpServerCgiFunc) handlers[i].handler, NULL, NULL); dsk_http_server_match_restore (server); } if (!dsk_http_server_bind_tcp (server, NULL, port, &error)) dsk_die ("error binding to port %u: %s", port, error->message); return dsk_main_run (); }
int main(int argc, char **argv) { unsigned i; char test_dir_buf[256]; DskError *error = NULL; dsk_cmdline_init ("test table internals (the 'file' abstraction)", "Test Table Internals", NULL, 0); dsk_cmdline_add_boolean ("verbose", "extra logging", NULL, 0, &cmdline_verbose); dsk_cmdline_add_boolean ("slow", "run tests that are fairly slow", NULL, 0, &cmdline_slow); dsk_cmdline_add_boolean ("keep-testdir", "do not delete working directory", NULL, 0, &cmdline_keep_testdir); dsk_cmdline_process_args (&argc, &argv); snprintf (test_dir_buf, sizeof (test_dir_buf), "test-table-file-%u-%u", (unsigned)time(NULL), (unsigned)getpid()); location = dsk_dir_new (NULL, test_dir_buf, DSK_DIR_NEW_MAYBE_CREATE, &error); if (location == NULL) dsk_die ("error making directory: %s", error->message); for (i = 0; i < DSK_N_ELEMENTS (tests); i++) { fprintf (stderr, "Test: %s... ", tests[i].name); tests[i].test (); fprintf (stderr, " done.\n"); } if (cmdline_keep_testdir) { fprintf (stderr, "test-table-file: keep-testdir: preserving test directory %s\n", dsk_dir_get_str (location)); } else { DskError *error = NULL; if (!dsk_remove_dir_recursive (dsk_dir_get_str (location), &error)) dsk_die ("error removing directory %s: %s", dsk_dir_get_str (location), error->message); } dsk_cleanup (); return 0; }
static DskHttpRequest * parse_request_from_string (const char *str) { DskError *error = NULL; DskHttpRequest *rv = try_parse_request_from_string (str, &error); if (rv == NULL) dsk_die ("error parsing request from string: %s", error->message); return rv; }
static void maybe_redirect_stdouterr (void) { if (dsk_daemon_log_template == NULL) return; time_t t = time (NULL); char buf[2048]; struct tm tm; t += dsk_daemon_tzoffset; gmtime_r (&t, &tm); strftime (buf, sizeof (buf), dsk_daemon_log_template, &tm); int fd; dsk_boolean made_dir = DSK_FALSE; retry_open: fd = open (buf, O_WRONLY|O_APPEND|O_CREAT, 0666); if (fd < 0) { if (errno == EINTR) goto retry_open; dsk_fd_creation_failed (errno); if (errno == ENOENT && !made_dir) { char *slash = strrchr (buf, '/'); if (slash != NULL) { char *dir = dsk_strdup_slice (buf, slash); DskError *error = NULL; if (!dsk_mkdir_recursive (dir, 0777, &error)) dsk_die ("error making directory %s: %s", dir, error->message); dsk_free (dir); } made_dir = DSK_TRUE; goto retry_open; } dsk_die ("error creating %s: %s", buf, strerror (errno)); } fflush (stdout); fflush (stderr); dup2 (fd, STDOUT_FILENO); dup2 (fd, STDERR_FILENO); close (fd); }
int main(int argc, char **argv) { DskPattern *pattern; DskError *error = NULL; dsk_cmdline_init ("grep-like tool", "Implement 'grep' using DskPattern", "PATTERN [FILES...]", DSK_CMDLINE_PERMIT_ARGUMENTS); dsk_cmdline_process_args (&argc, &argv); if (argc < 2) dsk_die ("missing pattern"); DskPatternEntry entry = { argv[1], "nonnull" }; pattern = dsk_pattern_compile (1, &entry, &error); if (pattern == NULL) dsk_die ("error compiling pattern: %s", error->message); unsigned buffer_size = isatty (STDOUT_FILENO) ? 0 : 8192; if (argc == 2) handle_fd (pattern, NULL, buffer_size, 0); else { int i; for (i = 2; i < argc; i++) { int fd = open (argv[i], O_RDONLY); if (fd < 0) dsk_die ("error opening %s: %s", argv[i], strerror (errno)); handle_fd (pattern, argc == 3 ? NULL : argv[i], buffer_size, fd); close (fd); } } return 0; }
static void begin_connecting (DskClientStream *stream) { if (stream->is_local_socket) { struct sockaddr_un addr; unsigned length = strlen (stream->name); if (length > sizeof (addr.sun_path)) { /* name too long */ /* TODO: catch this in constructor */ dsk_octet_stream_set_last_error (&stream->base_instance, "name too long for local socket"); return; } addr.sun_family = AF_LOCAL; memcpy (addr.sun_path, stream->name, length == sizeof (addr.sun_path) ? length : length + 1); begin_connecting_sockaddr (stream, sizeof (addr), (struct sockaddr *) &addr); } else if (stream->is_numeric_name) { struct sockaddr_storage addr; unsigned addr_len; DskIpAddress address; /* parse name into addr/addr_len */ if (!dsk_ip_address_parse_numeric (stream->name, &address)) dsk_die ("dsk_ip_address_parse_numeric failed on %s", stream->name); dsk_ip_address_to_sockaddr (&address, stream->port, &addr, &addr_len); begin_connecting_sockaddr (stream, addr_len, (struct sockaddr *) &addr); } else { /* begin dns lookup */ stream->is_resolving_name = 1; dsk_object_ref (stream); dsk_dns_lookup (stream->name, DSK_FALSE, /* is_ipv6? should be be needed */ handle_dns_done, stream); } }
static void test_simple_write_read (void) { DskError *error = NULL; DskTableFileInterface *iface = &dsk_table_file_interface_trivial; DskTableFileWriter *writer = iface->new_writer (iface, location, "base", &error); DskTableReader *reader; if (writer == NULL) dsk_die ("%s", error->message); if (!writer->write (writer, 1, (uint8_t*) "a", 1, (uint8_t*) "A", &error) || !writer->write (writer, 1, (uint8_t*) "b", 1, (uint8_t*) "B", &error) || !writer->write (writer, 1, (uint8_t*) "c", 1, (uint8_t*) "C", &error)) dsk_die ("error writing: %s", error->message); if (!writer->close (writer, &error)) dsk_die ("error closing writer: %s", error->message); writer->destroy (writer); reader = iface->new_reader (iface, location, "base", &error); if (reader == NULL) dsk_die ("error creating reader: %s", error->message); dsk_assert (!reader->at_eof); dsk_assert (reader->key_length == 1); dsk_assert (reader->key_data[0] == 'a'); dsk_assert (reader->value_length == 1); dsk_assert (reader->value_data[0] == 'A'); if (!reader->advance (reader, &error)) dsk_die ("error advancing reader: %s", error->message); dsk_assert (!reader->at_eof); dsk_assert (reader->key_length == 1); dsk_assert (reader->key_data[0] == 'b'); dsk_assert (reader->value_length == 1); dsk_assert (reader->value_data[0] == 'B'); if (!reader->advance (reader, &error)) dsk_die ("error advancing reader: %s", error->message); dsk_assert (!reader->at_eof); dsk_assert (reader->key_length == 1); dsk_assert (reader->key_data[0] == 'c'); dsk_assert (reader->value_length == 1); dsk_assert (reader->value_data[0] == 'C'); if (!reader->advance (reader, &error)) dsk_die ("error advancing reader: %s", error->message); dsk_assert (reader->at_eof); reader->destroy (reader); }
void dsk_daemon_maybe_fork (void) { int fork_pipe_fds[2] = {-1,-1}; if (dsk_daemon_do_fork) { int pid; retry_pipe: if (pipe (fork_pipe_fds) < 0) { if (errno == EINTR) goto retry_pipe; dsk_fd_creation_failed (errno); dsk_die ("error creating pipe: %s", strerror (errno)); } retry_daemon_fork: pid = fork (); if (pid < 0) { if (errno == EINTR) goto retry_daemon_fork; dsk_die ("error forking daemon: %s", strerror (errno)); } else if (pid > 0) { /* wait for EOF on pipe */ close (fork_pipe_fds[1]); char buf[1]; for (;;) { int nread = read (fork_pipe_fds[0], buf, 1); if (nread < 0) { if (errno == EINTR) continue; dsk_die ("error reading from semaphore pipe: %s", strerror (errno)); } else if (nread > 0) dsk_die ("somehow got data on semaphore pipe: %s:%u", __FILE__, __LINE__); else break; } _exit (0); } else { /* child process: continue as the non-forking case. */ close (fork_pipe_fds[0]); setsid (); } } int pid_file_fd = -1; if (dsk_daemon_pid_filename) { dsk_boolean must_truncate = DSK_FALSE; dsk_boolean made_dir = DSK_FALSE; retry_outer_pid_file_open: if ((pid_file_fd=open (dsk_daemon_pid_filename, O_CREAT|O_EXCL|O_WRONLY, 0666)) < 0) { if (errno == EINTR) goto retry_outer_pid_file_open; else if (errno == EEXIST) { /* open / lock-nonblocking / rewrite we get lock */ retry_inner_pid_file_open: if ((pid_file_fd=open (dsk_daemon_pid_filename, O_WRONLY, 0666)) < 0) { if (errno == EINTR) goto retry_inner_pid_file_open; dsk_die ("daemonize: error opening lock file %s: %s", dsk_daemon_pid_filename, strerror (errno)); } must_truncate = DSK_TRUE; } else if (errno == ENOENT && !made_dir) { /* make directories, retry */ char *slash = strrchr (dsk_daemon_pid_filename, '/'); if (slash == NULL) dsk_die ("daemonize: error creating %s: no such file or dir (cwd does not exist?)", dsk_daemon_pid_filename); char *dir = dsk_strdup_slice (dsk_daemon_pid_filename, slash); DskError *error = NULL; if (!dsk_mkdir_recursive (dir, 0777, &error)) dsk_die ("error making directory %s: %s", dir, error->message); dsk_free (dir); made_dir = DSK_TRUE; goto retry_outer_pid_file_open; } else { dsk_fd_creation_failed (errno); dsk_die ("daemonize: error creating PID file %s: %s", dsk_daemon_pid_filename, strerror (errno)); } } retry_flock: if (flock (pid_file_fd, LOCK_EX|LOCK_NB) < 0) { if (errno == EINTR) goto retry_flock; if (errno == EWOULDBLOCK) { /* TODO: print PID */ dsk_die ("daemonize: process already running"); } dsk_die ("daemonize: error locking: %s", strerror (errno)); } if (must_truncate) { ftruncate (pid_file_fd, 0); } char buf[32]; snprintf (buf, sizeof (buf), "%u\n", (unsigned)getpid ()); unsigned len = strlen (buf); unsigned written = 0; while (written < len) { int write_rv = write (pid_file_fd, buf + written, len - written); if (write_rv < 0) { if (errno == EINTR) continue; dsk_die ("error writing pid file %s", dsk_daemon_pid_filename); } written += write_rv; } } if (fork_pipe_fds[1] != -1) { close (fork_pipe_fds[1]); } if (dsk_daemon_watchdog) { int alert_pid = 0; unsigned last_alert_time = 0; for (;;) { /* NOTE: must never die, i guess */ int pid; int status; retry_watchdog_fork: pid = fork (); if (pid < 0) { if (errno == EINTR) goto retry_watchdog_fork; dsk_die ("error forking watchdogged process: %s", strerror (errno)); } else if (pid == 0) { if (pid_file_fd >= 0) close (pid_file_fd); maybe_redirect_stdouterr (); add_maybe_redirect_timer (); return; } maybe_redirect_stdouterr (); char time_str[TIME_STR_LENGTH]; make_time_str (time_str); fprintf (stderr, "%s: watchdog: forked process %u\n", time_str, (unsigned) pid); retry_waitpid: if (waitpid (pid, &status, 0) < 0) { if (errno == EINTR) goto retry_waitpid; dsk_die ("error running waitpid %u: %s", pid, strerror (errno)); } maybe_redirect_stdouterr (); make_time_str (time_str); if (WIFEXITED (status)) fprintf (stderr, "%s: watchdog: process %u exited with status %u\n", time_str, pid, WEXITSTATUS (status)); else if (WIFSIGNALED (status)) fprintf (stderr, "%s: watchdog: process %u killed by signal %u%s\n", time_str, pid, WTERMSIG (status), WCOREDUMP (status) ? " [core dumped]" : ""); else fprintf (stderr, "%s: watchdog: process %u died in some creative way\n", time_str, pid); /* configurable? */ sleep (1); /* send alert */ if (dsk_daemon_alert_script) { int time_delta = time (NULL) - last_alert_time; unsigned clamped_delta = time_delta < 0 ? 0 : time_delta; if (alert_pid > 0) { int rv = waitpid (alert_pid, &status, WNOHANG); if (rv < 0) { if (errno == EINTR) goto retry_waitpid; else dsk_die ("error waiting for alert process"); } else if (rv == 0) { /* process has not terminated */ } else { /* process terminated (ignore status?) */ alert_pid = 0; } } if (alert_pid == 0 && clamped_delta > dsk_daemon_alert_interval) { retry_alert_fork: alert_pid = fork (); if (alert_pid < 0) { if (errno == EINTR) goto retry_alert_fork; dsk_warning ("error forking alert process: %s", strerror (errno)); alert_pid = 0; } else if (alert_pid == 0) { execl ("/bin/sh", "/bin/sh", "-c", dsk_daemon_alert_script, NULL); _exit (127); } else dsk_daemon_n_alerts_suppressed = 0; } else ++dsk_daemon_n_alerts_suppressed; } } } }
static void test_various_write_seek_1 (const char *name, unsigned n_entries, TestEntry *entries, unsigned n_negative, TestEntry *neg_entries) { DskError *error = NULL; unsigned i; DskTableFileInterface *iface = &dsk_table_file_interface_trivial; DskTableFileWriter *writer; DskTableFileSeeker *seeker; if (cmdline_verbose) fprintf (stderr, "running dataset %s [%u]\n", name, n_entries); else fprintf (stderr, "."); writer = iface->new_writer (iface, location, "base", &error); if (writer == NULL) dsk_die ("%s", error->message); for (i = 0; i < n_entries; i++) { TestEntry *e = entries + i; if (!writer->write (writer, strlen (e->key), (uint8_t*) e->key, strlen (e->value), (uint8_t*) e->value, &error)) dsk_die ("error writing: %s", error->message); } if (!writer->close (writer, &error)) dsk_die ("error closing writer: %s", error->message); writer->destroy (writer); /* --- now test seeker --- */ /* pick the step size. */ { static unsigned prime_table[] = { 29, 31, 37, 41, 43, 47, 53, 59, 61, 67 }; unsigned *p_ptr = prime_table + DSK_N_ELEMENTS (prime_table) - 1; unsigned max_test, n_test, test_i, step; while (n_entries % *p_ptr == 0) p_ptr--; step = *p_ptr % n_entries; /* create seeker */ seeker = iface->new_seeker (iface, location, "base", &error); if (seeker == NULL) dsk_die ("error creating seeker from newly finished writer: %s", error->message); max_test = cmdline_slow ? 100000 : 1000; n_test = DSK_MIN (n_entries, max_test); test_i = step; for (i = 0; i < n_test; i++) { unsigned key_len, value_len; const uint8_t *key_data, *value_data; /* do the seek */ if (!seeker->find (seeker, str_test_func, (void*) entries[test_i].key, DSK_TABLE_FILE_FIND_ANY, &key_len, &key_data, &value_len, &value_data, &error)) { if (error) dsk_die ("error doing find that should have succeeded: %s", error->message); else dsk_die ("not found doing find that should have succeeded"); } #if 0 dsk_warning ("test=%s, got result %.*s", entries[test_i].key, (int) key_len, key_data); #endif dsk_assert (key_len == strlen (entries[test_i].key)); dsk_assert (value_len == strlen (entries[test_i].value)); dsk_assert (memcmp (key_data, entries[test_i].key, key_len) == 0); dsk_assert (memcmp (value_data, entries[test_i].value, value_len) == 0); /* advance test_i */ test_i += step; if (test_i >= n_entries) test_i -= n_entries; } /* do negative tests */ for (i = 0; i < n_negative; i++) { unsigned key_len, value_len; const uint8_t *key_data, *value_data; /* do the seek */ if (!seeker->find (seeker, str_test_func, (void*) neg_entries[i].key, DSK_TABLE_FILE_FIND_ANY, &key_len, &key_data, &value_len, &value_data, &error)) { if (error) dsk_die ("error doing find that should have returned nothing: %s", error->message); } else if (key_len == strlen (neg_entries[i].key) && memcmp (key_data, neg_entries[i].key, key_len) == 0) { dsk_die ("found result when none expected"); } } seeker->destroy (seeker); } }