From: Andre Noll Date: Sat, 18 Nov 2017 14:54:03 +0000 (+0100) Subject: Merge branch 'refs/heads/t/kill-w' X-Git-Tag: v1.0.0~7 X-Git-Url: http://git.tuebingen.mpg.de/?p=dss.git;a=commitdiff_plain;h=324d1364004376fa0b018afcb57cfe14aca7fcdb;hp=faed24aec8859d232fe3c0da415265e0de099ce4 Merge branch 'refs/heads/t/kill-w' Two patches which make life easier for shutdown scripts which need to terminate the dss process, but would like to wait until the exit hook completed. The merge conflicted in dss.suite, but this was trivial to fix. Cooking for a week. * refs/heads/t/kill-w: kill: New option --wait. run: Wait for children to die. --- diff --git a/.gitignore b/.gitignore index 977f1dc..1bb2a25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ Makefile.deps -*.[oa] -cmdline.[ch] +*.o +*.swp dss.lsg.* dss dss.1 dss.1.html +dss.png +index.html diff --git a/INSTALL b/INSTALL index 8c70c34..09d8505 100644 --- a/INSTALL +++ b/INSTALL @@ -24,7 +24,7 @@ to install in /usr/local, or to install in /somewhere/else. -Also make sure that [rsync](http://rsync.samba.org/) is installed on +Also make sure that [rsync](https://rsync.samba.org/) is installed on your system. Version 2.6.1 or newer is required. Examples: @@ -70,7 +70,7 @@ system boundaries and increases the number of snapshots. rsync-option "--exclude-from=/etc/dss.exclude" # don't cross filesystem boundaries rsync-option "--one-file-system" - # maintain 2^6 - 1 = 63 snaphots + # maintain 2^6 - 1 = 63 snapshots num-intervals "6" The /etc/dss.exclude file could look like this (see rsync(1) for diff --git a/Makefile b/Makefile index a8e045c..f5c34af 100644 --- a/Makefile +++ b/Makefile @@ -37,8 +37,8 @@ dss: $(dss_objects) %.o: %.c Makefile $(CC) -c $(DSS_CPPFLAGS) $(CPPFLAGS) $(DSS_CFLAGS) $(CFLAGS) $< -%.png: %.dia - dia -e $@ -t png $< +dss.png: mklogo + ./mklogo > $@ %.lsg.h: %.suite lopsubgen --gen-h=$@ < $< diff --git a/NEWS b/NEWS index 755cad2..0f9b6d2 100644 --- a/NEWS +++ b/NEWS @@ -1,26 +1,49 @@ ----------------------- -x.y.z (to be announced) +1.0.0 (to be announced) ----------------------- - - Improved error diagnostics for the kill subcommand. + - The gengetopt option parser has been replaced by the + [lopsub](http://people.tuebingen.mpg.de/maan/lopsub) library. Hence + lopsub must be installed to compile this package. help2man is + no longer required since lopsub has built-in roff support. + + - New subcommand "configtest" to check the command line options and + the configuration file for syntactic correctness. + + - New option: --mountpoint. If this option is given, dss aborts if + no file system is mounted on the destination directory. + + - New option --checksum to let rsync compute checksums occasionally. + + - The kill subcommand gained the new --wait option which instructs dss + to wait until the signalled process has terminated. - The --no-resume option has been removed. - - The gengetopt option parser has been replaced by the - [lopsub](http://people.tuebingen.mpg.de/~maan/lopsub) library. Hence - lopsub must be installed to compile this package. Also help2man is - no longer required since lopsub has built-in roff support. + - On exit, the run subcommand now waits for any previously spawned + rsync or rm processes to terminate. - - "make install" will install the executable and the man page. + - The ls subcommand now shows the age of incomplete snapshots rather + than 0:00. - In run mode, dss no longer exits successfully if another instance is already running. - - New option --checksum to let rsync compute checksums occasionally. + - The command specified as the argument to --exit-hook is now subject + to word splitting. Previously, the string was executed as-is. + + - Improved error diagnostics for the kill subcommand. + + - For all subcommands other than "run", timestamps and function names + are omitted from the log output. + + - "make install" will install the executable and the man page. - CFLAGS, CPPFLAGS and LDFLAGS can now be used to override the flags of the build system. + - The dss logo is now created with ImageMagick rather than dia. + ------------------ 0.1.7 (2017-04-17) ------------------ diff --git a/README b/README index c5abb29..79b8889 100644 --- a/README +++ b/README @@ -11,7 +11,7 @@ configured, and there is no database to maintain. dss is also user-friendly because users can browse the snapshot directories without admin intervention and see the contents of the file -system at the various times a snapshot was taken. Each snaphot looks +system at the various times a snapshot was taken. Each snapshot looks like a full backup, so users can easily restore accidentally removed files by using their favorite file browser to simply copy files from the snapshot directory back to the live system. diff --git a/df.c b/df.c index 003becc..82d14ba 100644 --- a/df.c +++ b/df.c @@ -18,7 +18,7 @@ int get_disk_space(const char *path, struct disk_space *result) { - /* using floats allows to not care about integer overflows */ + /* With floats we don't need to care about integer overflows. */ float total_blocks, available_blocks, blocksize; float total_inodes, available_inodes; diff --git a/dss.c b/dss.c index 60c0591..491b8aa 100644 --- a/dss.c +++ b/dss.c @@ -63,6 +63,8 @@ static struct lls_parse_result *cmdline_lpr, *lpr; /** Parsed subcommand options. */ static struct lls_parse_result *cmdline_sublpr, *sublpr; +/* The executing subcommand (NULL at startup). */ +static const struct lls_command *subcmd; /** Wether daemon_init() was called. */ static bool daemonized; /** Non-NULL if we log to a file. */ @@ -242,16 +244,19 @@ __printf_1_2 void dss_log(const char* fmt,...) if (loglevel < lpr_ll) return; outfd = logfile? logfile : stderr; - time(&t1); - tm = localtime(&t1); - strftime(str, sizeof(str), "%b %d %H:%M:%S", tm); - fprintf(outfd, "%s ", str); - if (lpr_ll <= INFO) - fprintf(outfd, "%i: ", loglevel); + if (subcmd == CMD_PTR(RUN)) { + time(&t1); + tm = localtime(&t1); + strftime(str, sizeof(str), "%b %d %H:%M:%S", tm); + fprintf(outfd, "%s ", str); + if (lpr_ll <= INFO) + fprintf(outfd, "%i: ", loglevel); + } + if (subcmd == CMD_PTR(RUN)) #ifdef DSS_NO_FUNC_NAMES - fprintf(outfd, "%s:%d: ", location_file, location_line); + fprintf(outfd, "%s:%d: ", location_file, location_line); #else - fprintf(outfd, "%s: ", location_func); + fprintf(outfd, "%s: ", location_func); #endif va_start(argp, fmt); vfprintf(outfd, fmt, argp); @@ -297,6 +302,7 @@ static int send_signal(int sig, bool wait) dss_msg("%d\n", (int)pid); return 0; } + DSS_NOTICE_LOG(("sending signal %d to pid %d\n", sig, (int)pid)); ret = kill(pid, sig); if (ret < 0) return -ERRNO_TO_DSS_ERROR(errno); @@ -534,7 +540,7 @@ static struct snapshot *find_orphaned_snapshot(struct snapshot_list *sl) struct snapshot *s; int i; - DSS_DEBUG_LOG(("looking for orphaned snapshots\n")); + DSS_DEBUG_LOG(("looking for old incomplete snapshots\n")); FOR_EACH_SNAPSHOT(s, i, sl) { if (snapshot_is_being_created(s)) continue; @@ -748,6 +754,7 @@ static int try_to_free_disk_space(void) if (!low_disk_space) goto out; DSS_WARNING_LOG(("disk space low and nothing obvious to remove\n")); + why = "oldest"; victim = find_oldest_removable_snapshot(&sl); if (victim) goto remove; @@ -1072,20 +1079,39 @@ static int handle_sigchld(void) return -E_BUG; } +/* also checks if . is a mountpoint, if --mountpoint was given */ static int change_to_dest_dir(void) { int ret; const char *dd = OPT_STRING_VAL(DSS, DEST_DIR); + struct stat dot, dotdot; DSS_INFO_LOG(("changing cwd to %s\n", dd)); - if (chdir(dd) >= 0) - return 1; - ret = -ERRNO_TO_DSS_ERROR(errno); - DSS_ERROR_LOG(("could not change cwd to %s\n", dd)); - return ret; + if (chdir(dd) < 0) { + ret = -ERRNO_TO_DSS_ERROR(errno); + DSS_ERROR_LOG(("could not change cwd to %s\n", dd)); + return ret; + } + if (!OPT_GIVEN(DSS, MOUNTPOINT)) + return 0; + if (stat(".", &dot) < 0) { + ret = -ERRNO_TO_DSS_ERROR(errno); + DSS_ERROR_LOG(("could not stat .\n")); + return ret; + } + if (stat("..", &dotdot) < 0) { + ret = -ERRNO_TO_DSS_ERROR(errno); + DSS_ERROR_LOG(("could not stat ..\n")); + return ret; + } + if (dot.st_dev == dotdot.st_dev && dot.st_ino != dotdot.st_ino) { + DSS_ERROR_LOG(("mountpoint check failed for %s\n", dd)); + return -E_MOUNTPOINT; + } + return 1; } -static int check_config(const struct lls_command *cmd) +static int check_config(void) { int ret; uint32_t unit_interval = OPT_UINT32_VAL(DSS, UNIT_INTERVAL); @@ -1101,13 +1127,13 @@ static int check_config(const struct lls_command *cmd) DSS_ERROR_LOG(("bad number of intervals: %i\n", num_intervals)); return -E_INVALID_NUMBER; } - if (cmd == CMD_PTR(RUN) || cmd == CMD_PTR(CREATE)) + if (subcmd == CMD_PTR(RUN) || subcmd == CMD_PTR(CREATE)) if (!OPT_GIVEN(DSS, SOURCE_DIR)) { DSS_ERROR_LOG(("--source-dir required\n")); return -E_SYNTAX; } - if (cmd == CMD_PTR(RUN) || cmd == CMD_PTR(CREATE) - || cmd == CMD_PTR(LS) || cmd == CMD_PTR(PRUNE)) { + if (subcmd == CMD_PTR(RUN) || subcmd == CMD_PTR(CREATE) + || subcmd == CMD_PTR(LS) || subcmd == CMD_PTR(PRUNE)) { if (!OPT_GIVEN(DSS, DEST_DIR)) { DSS_ERROR_LOG(("--dest-dir required\n")); return -E_SYNTAX; @@ -1245,7 +1271,7 @@ static int handle_sighup(void) ret = parse_config_file(true /* SIGHUP */, CMD_PTR(RUN)); if (ret < 0) return ret; - ret = check_config(CMD_PTR(RUN)); + ret = check_config(); if (ret < 0) return ret; close_log(logfile); @@ -1519,15 +1545,18 @@ out: static void exit_hook(int exit_code) { - const char *argv[3]; pid_t pid; - - argv[0] = OPT_STRING_VAL(DSS, EXIT_HOOK); - argv[1] = dss_strerror(-exit_code); - argv[2] = NULL; - - DSS_NOTICE_LOG(("executing %s %s\n", argv[0], argv[1])); - dss_exec(&pid, argv[0], (char **)argv); + char **argv, *tmp = dss_strdup(OPT_STRING_VAL(DSS, EXIT_HOOK)); + unsigned n = split_args(tmp, &argv, " \t"); + + n++; + argv = dss_realloc(argv, (n + 1) * sizeof(char *)); + argv[n - 1] = dss_strdup(dss_strerror(-exit_code)); + argv[n] = NULL; + dss_exec(&pid, argv[0], argv); + free(argv[n - 1]); + free(argv); + free(tmp); } static void lock_dss_or_die(void) @@ -1704,19 +1733,30 @@ static int com_ls(void) int i; struct snapshot_list sl; struct snapshot *s; + int64_t now = get_current_time(); dss_get_snapshot_list(&sl); FOR_EACH_SNAPSHOT(s, i, &sl) { - int64_t d = 0; + int64_t d; if (s->flags & SS_COMPLETE) d = (s->completion_time - s->creation_time) / 60; - dss_msg("%u\t%s\t%3" PRId64 ":%02" PRId64 "\n", s->interval, s->name, d/60, d%60); + else + d = (now - s->creation_time) / 60; + dss_msg("%u\t%s\t%3" PRId64 ":%02" PRId64 "\n", s->interval, + s->name, d / 60, d % 60); } free_snapshot_list(&sl); return 1; } EXPORT_CMD_HANDLER(ls); +static int com_configtest(void) +{ + printf("Syntax Ok\n"); + return 0; +} +EXPORT_CMD_HANDLER(configtest); + static int setup_signal_handling(void) { int ret; @@ -1758,7 +1798,7 @@ static void show_subcommand_summary(void) for (i = 1; (cmd = lls_cmd(i, dss_suite)); i++) { const char *name = lls_command_name(cmd); const char *purpose = lls_purpose(cmd); - printf("%-10s%s\n", name, purpose); + printf("%-11s%s\n", name, purpose); } exit(EXIT_SUCCESS); } @@ -1766,18 +1806,17 @@ static void show_subcommand_summary(void) int main(int argc, char **argv) { int ret; - const struct lls_command *cmd = CMD_PTR(DSS); char *errctx = NULL; unsigned num_inputs; - const struct dss_user_data *ud = NULL; + const struct dss_user_data *ud; - ret = lls_parse(argc, argv, cmd, &cmdline_lpr, &errctx); + ret = lls_parse(argc, argv, CMD_PTR(DSS), &cmdline_lpr, &errctx); if (ret < 0) { ret = lopsub_error(ret, &errctx); goto out; } lpr = cmdline_lpr; - ret = parse_config_file(false /* no SIGHUP */, cmd); + ret = parse_config_file(false /* no SIGHUP */, CMD_PTR(DSS)); if (ret < 0) goto out; handle_version_and_help(); @@ -1789,24 +1828,24 @@ int main(int argc, char **argv) ret = lopsub_error(ret, &errctx); goto out; } - cmd = lls_cmd(ret, dss_suite); - ret = lls_parse(num_inputs, argv + argc - num_inputs, cmd, + subcmd = lls_cmd(ret, dss_suite); + ret = lls_parse(num_inputs, argv + argc - num_inputs, subcmd, &cmdline_sublpr, &errctx); if (ret < 0) { ret = lopsub_error(ret, &errctx); goto out; } sublpr = cmdline_sublpr; - ret = parse_config_file(false /* no SIGHUP */, cmd); + ret = parse_config_file(false /* no SIGHUP */, subcmd); if (ret < 0) goto out; - ret = check_config(cmd); + ret = check_config(); if (ret < 0) goto out; ret = setup_signal_handling(); if (ret < 0) goto out; - ud = lls_user_data(cmd); + ud = lls_user_data(subcmd); ret = ud->handler(); signal_shutdown(); out: @@ -1819,8 +1858,8 @@ out: lls_free_parse_result(lpr, CMD_PTR(DSS)); if (lpr != cmdline_lpr) lls_free_parse_result(cmdline_lpr, CMD_PTR(DSS)); - lls_free_parse_result(sublpr, cmd); + lls_free_parse_result(sublpr, subcmd); if (sublpr != cmdline_sublpr) - lls_free_parse_result(cmdline_sublpr, cmd); + lls_free_parse_result(cmdline_sublpr, subcmd); exit(ret >= 0? EXIT_SUCCESS : EXIT_FAILURE); } diff --git a/dss.dia b/dss.dia deleted file mode 100644 index a02f700..0000000 --- a/dss.dia +++ /dev/null @@ -1,960 +0,0 @@ - - - - - - - - - - - - - #A4# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #DSS# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dss.suite b/dss.suite index d4926c3..f02c825 100644 --- a/dss.suite +++ b/dss.suite @@ -34,7 +34,7 @@ caption = Subcommands However, there is one exception to this rule: The run subcommand re-reads the configuration file when it receives the HUP signal. In this case the options in the config file override any options that - were previously given at the command line. This allows to change the + were previously given at the command line. This allows changing the configuration of a running dss process by sending SIGHUP. [/help] [option loglevel] @@ -79,6 +79,18 @@ caption = Subcommands This option is mandatory for all subcommands except kill. [/help] + [option mountpoint] + summary = abort if destination directory is not a mountpoint + [help] + This option checks whether a file system is mounted on the directory + specified as the argument to --dest-dir. Operation proceeds only + if this is the case. Otherwise dss exits unsuccessfully without + performing any action. Use this option to prevent snapshot creation + if the snapshot file system is not mounted. + + This option is silently ignored for subcommands which do not depend + on the destination directory. + [/help] [option Rsync-options] summary = Controlling how rsync is run flag ignored @@ -312,8 +324,8 @@ caption = Subcommands typestr = percent default_val = 2 [help] - This is like --min-free-mb but allows to specify the amount of - free disk space as a percentage. It is not recommended to set both + This is like --min-free-mb but the amount of free disk space + is specified as a percentage. It is not recommended to set both --min-free-mb and --min-free-percent to zero as this will cause your file system to fill up quickly. [/help] @@ -496,6 +508,14 @@ caption = Subcommands It makes only sense to use the option for signals which terminate dss. [/help] +[subcommand configtest] + purpose = run a configuration file syntax test + [description] + This command checks the command line options and the configuration + file for syntactic correctness. It either reports "Syntax Ok" and + exits successfully or prints information about the first syntax error + detected and terminates with exit code 1. + [/description] [section copyright] Written by Andre Noll diff --git a/err.h b/err.h index c3e207e..2280010 100644 --- a/err.h +++ b/err.h @@ -48,6 +48,7 @@ static inline char *dss_strerror(int num) DSS_ERROR(INVALID_NUMBER, "invalid number"), \ DSS_ERROR(STRFTIME, "strftime() failed"), \ DSS_ERROR(LOCALTIME, "localtime() failed"), \ + DSS_ERROR(MOUNTPOINT, "destination directory is no mountpoint"), \ DSS_ERROR(NULL_OPEN, "can not open /dev/null"), \ DSS_ERROR(DUP_PIPE, "exec error: can not create pipe"), \ DSS_ERROR(INVOLUNTARY_EXIT, "unexpected termination cause"), \ diff --git a/file.h b/file.h index 140a505..f82643a 100644 --- a/file.h +++ b/file.h @@ -5,17 +5,7 @@ */ int for_each_subdir(int (*func)(const char *, void *), void *private_data); __must_check int mark_fd_nonblocking(int fd); -/** - * A wrapper for rename(2). - * - * \param old_path The source path. - * \param new_path The destination path. - * - * \return Standard. - * - * \sa rename(2). - */ -_static_inline_ int dss_rename(const char *old_path, const char *new_path) +static inline int dss_rename(const char *old_path, const char *new_path) { if (rename(old_path, new_path) >= 0) return 1; diff --git a/gcc-compat.h b/gcc-compat.h index a15b0ce..258a3cb 100644 --- a/gcc-compat.h +++ b/gcc-compat.h @@ -2,24 +2,12 @@ defined(__GNUC__) && \ (__GNUC__ > maj || (__GNUC__ == maj && __GNUC_MINOR__ >= min)) -#if HAVE_GNUC(2,5) -# define __noreturn __attribute__ ((noreturn)) -#else -# define __noreturn -#endif - #if HAVE_GNUC(3,0) # define __malloc __attribute__ ((malloc)) #else # define __malloc #endif -#if HAVE_GNUC(2,7) -# define __a_unused __attribute__ ((unused)) -#else -# define __a_unused -#endif - /* * p is the number of the "format string" parameter, and q is * the number of the first variadic parameter @@ -30,17 +18,10 @@ # define __printf(p,q) #endif -/* - * as direct use of __printf(p,q) confuses doxygen, here are two extra macros - * for those values p,q that are actually used by paraslash. - */ #define __printf_1_2 __printf(1,2) -#define __printf_2_3 __printf(2,3) #if HAVE_GNUC(3,3) # define __must_check __attribute__ ((warn_unused_result)) #else # define __must_check /* no warn_unused_result */ #endif - -#define _static_inline_ static inline diff --git a/mklogo b/mklogo new file mode 100755 index 0000000..54c8c95 --- /dev/null +++ b/mklogo @@ -0,0 +1,100 @@ +#!/bin/bash + +# Script for Image Magick that writes the dss logo in png format +# to stdout. + +set -u + +width=320 +height=110 +border=5 +radius1=4 +radius2=5 +circle_y=90 +arrow_y=70 +text_x=128 +text_y=55 +pointsize=36 + +declare -a circle arrow rectangle text + +make_circles() +{ + local inner='stroke black fill red circle' + local outer='stroke black fill black circle' + local num=1 + local idx=0 + local y=$circle_y + local step x0 i j idx num + + for ((i = 0; i < 4; i++)); do + step=$(((width / 4 + num) / (num + 1))) + x0=$((border + width / 4 * i)) + for ((j = 1; j <= $num; j++)); do + x=$((x0 + j * $step)) + circle[$idx]='-draw'; let idx++ + circle[$idx]="$outer $x,$y,$((x + radius2)),$y"; let idx++ + circle[$idx]='-draw'; let idx++ + circle[$idx]="$inner $x,$y,$((x + radius1)),$y"; let idx++ + done + num=$((num * 2)) + done + #echo "${circle[@]}"; exit 0 +} + +make_arrow() +{ + local arrow_head='l -15,-5 +5,+5 -5,+5 +15,-5 z' + local idx=0 + local x0 x1 y + + arrow[$idx]='-draw'; let idx++ + x0=$((3 * border)); x1=$((width - 2 * border)) + y=$arrow_y + arrow[$idx]="stroke white line $x0,$y $x1,$y"; let idx++ + arrow[$idx]='-draw'; let idx++ + x0=$((width - 2 * border)) + arrow[$idx]="stroke white fill white path 'M $x0,$y $arrow_head'" + #echo "${arrow[@]}"; exit 0 +} + +make_rectangles() +{ + local idx=0 + local x x0 x1 y y0 y1 i red_green color + + rectangle[$idx]='-draw'; let idx++ + x=$((width + 2 * border)) + y=$((height + 2 * border)) + rectangle[$idx]="stroke yellow fill yellow rectangle 0,0 $x,$y"; let idx++ + for ((i = 0; i < 4; i++)); do + rectangle[$idx]='-draw'; let idx++ + red_green="$(printf '%02x' $(((3 - i) * 60)))" + color="#${red_green}${red_green}ff" + x0=$((border + i * width / 4)); x1=$((x0 + width / 4 - 1)) + y0=$border; y1=$((y0 + height)) + rectangle[$idx]="stroke $color fill $color rectangle $x0,$y0 $x1,$y1" + let idx++ + done + #echo "${rectangle[@]}"; exit 0 +} + +make_text() +{ + text=(-pointsize $pointsize -draw \ + "fill white text $text_x,$text_y DSS") + #echo "${text[@]}"; exit 0 +} + +make_rectangles +make_arrow +make_circles +make_text + +convert -size $((width + 2 * border))x$((height + 2 * border)) \ + -background none xc: \ + "${rectangle[@]}" \ + "${arrow[@]}" \ + "${circle[@]}" \ + "${text[@]}" \ + png:- diff --git a/snap.h b/snap.h index 626ecad..489b67a 100644 --- a/snap.h +++ b/snap.h @@ -93,7 +93,7 @@ int num_complete_snapshots(struct snapshot_list *sl); /** * Get the newest snapshot in a snapshot list. */ -_static_inline_ struct snapshot *get_newest_snapshot(struct snapshot_list *sl) +static inline struct snapshot *get_newest_snapshot(struct snapshot_list *sl) { if (!sl->num_snapshots) return NULL; diff --git a/tv.c b/tv.c index 8ab5e5a..f954cef 100644 --- a/tv.c +++ b/tv.c @@ -54,6 +54,5 @@ int64_t get_current_time(void) { time_t now; time(&now); - DSS_DEBUG_LOG(("now: %jd\n", (intmax_t)now)); return (int64_t)now; }