Skip to content

Instantly share code, notes, and snippets.

@DosAmp
Last active April 7, 2019 12:27
Show Gist options
  • Save DosAmp/d2cc793ec6c5272fd47af0abace7a569 to your computer and use it in GitHub Desktop.
Save DosAmp/d2cc793ec6c5272fd47af0abace7a569 to your computer and use it in GitHub Desktop.
Simple shell-script counter without lockfile
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <libgen.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
/* strlen("-9223372036854775808\n") == 21 */
#define MMAP_LEN 21
static const char default_counter[] = ".dotcount";
int main(int argc, char *argv[])
{
int ret = 0;
int replaced = 0;
char *counterfile = (char *) default_counter;
if (argc > 1) {
counterfile = argv[1];
}
int cfd = open(counterfile, O_RDONLY | O_CLOEXEC, 0);
if (cfd == -1) {
ret = EXIT_FAILURE;
goto end;
}
void *cmap = mmap(NULL, MMAP_LEN, PROT_READ, MAP_FILE, cfd, 0);
if (cmap == MAP_FAILED) {
ret = EXIT_FAILURE;
goto end;
}
char *stablecountend;
long stablecount = strtol((const char *) cmap, &stablecountend, 10);
if (*stablecountend == '\n') {
stablecountend++;
}
off_t stablecountlen = (off_t)(stablecountend-(char*)cmap);
munmap(cmap, MMAP_LEN);
cmap = NULL;
off_t filelen = lseek(cfd, 0, SEEK_END);
close(cfd);
cfd = -1;
long linecount = (long)(filelen-stablecountlen);
if (linecount < 0) {
linecount = 0;
}
char *parent = dirname(counterfile);
/* strlen("/.new.XXXXXX") = 12 */
char *newtemplate = malloc(strlen(parent) + 13);
if (!newtemplate) {
ret = EXIT_FAILURE;
goto end;
}
strcpy(newtemplate, parent);
strcat(newtemplate, "/.new.XXXXXX");
int nfd = mkostemp(newtemplate, O_CLOEXEC);
if (nfd == -1) {
ret = EXIT_FAILURE;
goto end;
}
FILE *nfil = fdopen(nfd, "w");
if (fprintf(nfil, "%ld\n", (stablecount + linecount)) > 0) {
fclose(nfil);
nfd = -1;
replaced = rename(newtemplate, counterfile) == 0;
} else {
/* nothing written, nothing to flush */
ret = EXIT_FAILURE;
}
end:
if (nfd > -1) {
close(nfd);
if (!replaced) {
unlink(newtemplate);
}
}
if (cmap != MAP_FAILED && cmap) {
munmap(cmap, MMAP_LEN);
}
if (cfd > -1) {
close(cfd);
}
if (newtemplate) {
free(newtemplate);
}
return ret;
}
#!/bin/ksh
# initialize with echo 0 > .dotcount
DOTCOUNT=.dotcount
MINDIGITS=6
stablecount="$(head -n 1 "$DOTCOUNT" 2>/dev/null)"
if [ -z "$stablecount" ]; then
# no stable count, count as if there was one
stablecount=1
fi
# appending/creating is a race-free operation
echo >> "$DOTCOUNT"
# linecount contains stablecount + number of all newlines since then
linecount=$(wc -l < "$DOTCOUNT")
# therefore subtract one
count=$((${stablecount}+${linecount}-1))
echo "Content-Type: text/html"
echo
echo '<head><style>html,body{margin: 0}pre{text-align:right}</style></head>'
printf "<body><pre>%0${MINDIGITS}d</pre></body>\n" $count
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment