Merge branch 'jc/bare'
authorJunio C Hamano <junkio@cox.net>
Fri, 12 Jan 2007 00:50:36 +0000 (16:50 -0800)
committerJunio C Hamano <junkio@cox.net>
Fri, 12 Jan 2007 00:50:36 +0000 (16:50 -0800)
* jc/bare:
Disallow working directory commands in a bare repository.
git-fetch: allow updating the current branch in a bare repository.
Introduce is_bare_repository() and core.bare configuration variable
Move initialization of log_all_ref_updates

1  2 
cache.h
config.c
git-am.sh
git-checkout.sh
git-commit.sh
git.c
refs.c
diff --combined cache.h
index cbe398d3bdea235c2b1c22664b598699f77d37c9,cff25690f1861fd947b036e17cbefea783a7fbfc..c482c32a03ebc55a293aa96c8add08abf355f2ea
+++ b/cache.h
@@@ -127,7 -127,8 +127,8 @@@ extern int cache_errno
  #define CONFIG_LOCAL_ENVIRONMENT "GIT_CONFIG_LOCAL"
  #define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
  
- extern int is_bare_git_dir(const char *dir);
+ extern int is_bare_repository_cfg;
+ extern int is_bare_repository(void);
  extern const char *get_git_dir(void);
  extern char *get_object_directory(void);
  extern char *get_refs_directory(void);
@@@ -299,7 -300,7 +300,7 @@@ extern char *sha1_to_hex(const unsigne
  extern int read_ref(const char *filename, unsigned char *sha1);
  extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
  extern int create_symref(const char *ref, const char *refs_heads_master);
 -extern int validate_symref(const char *ref);
 +extern int validate_headref(const char *ref);
  
  extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
  extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
@@@ -432,12 -433,10 +433,12 @@@ extern char *git_commit_encoding
  extern char *git_log_output_encoding;
  
  extern int copy_fd(int ifd, int ofd);
 +extern int read_in_full(int fd, void *buf, size_t count);
  extern void read_or_die(int fd, void *buf, size_t count);
 -extern int write_in_full(int fd, const void *buf, size_t count, const char *);
 +extern int write_in_full(int fd, const void *buf, size_t count);
  extern void write_or_die(int fd, const void *buf, size_t count);
  extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
 +extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
  
  /* pager.c */
  extern void setup_pager(void);
diff --combined config.c
index 733fb1a34cf809c79c86bc6f7136e9d98ef6cdf9,20e6ecc361325447f5784aba421f7f1588be184c..b6082f597c118d75a9342d1e0bf5788c7a8257ee
+++ b/config.c
@@@ -269,6 -269,11 +269,11 @@@ int git_default_config(const char *var
                return 0;
        }
  
+       if (!strcmp(var, "core.bare")) {
+               is_bare_repository_cfg = git_config_bool(var, value);
+               return 0;
+       }
        if (!strcmp(var, "core.ignorestat")) {
                assume_unchanged = git_config_bool(var, value);
                return 0;
@@@ -464,15 -469,7 +469,15 @@@ static int store_aux(const char* key, c
        return 0;
  }
  
 -static void store_write_section(int fd, const char* key)
 +static int write_error()
 +{
 +      fprintf(stderr, "Failed to write new configuration file\n");
 +
 +      /* Same error code as "failed to rename". */
 +      return 4;
 +}
 +
 +static int store_write_section(int fd, const char* key)
  {
        const char *dot = strchr(key, '.');
        int len1 = store.baselen, len2 = -1;
                }
        }
  
 -      write(fd, "[", 1);
 -      write(fd, key, len1);
 +      if (write_in_full(fd, "[", 1) != 1 ||
 +          write_in_full(fd, key, len1) != len1)
 +              return 0;
        if (len2 >= 0) {
 -              write(fd, " \"", 2);
 +              if (write_in_full(fd, " \"", 2) != 2)
 +                      return 0;
                while (--len2 >= 0) {
                        unsigned char c = *++dot;
                        if (c == '"')
 -                              write(fd, "\\", 1);
 -                      write(fd, &c, 1);
 +                              if (write_in_full(fd, "\\", 1) != 1)
 +                                      return 0;
 +                      if (write_in_full(fd, &c, 1) != 1)
 +                              return 0;
                }
 -              write(fd, "\"", 1);
 +              if (write_in_full(fd, "\"", 1) != 1)
 +                      return 0;
        }
 -      write(fd, "]\n", 2);
 +      if (write_in_full(fd, "]\n", 2) != 2)
 +              return 0;
 +
 +      return 1;
  }
  
 -static void store_write_pair(int fd, const char* key, const char* value)
 +static int store_write_pair(int fd, const char* key, const char* value)
  {
        int i;
 +      int length = strlen(key+store.baselen+1);
 +      int quote = 0;
  
 -      write(fd, "\t", 1);
 -      write(fd, key+store.baselen+1,
 -              strlen(key+store.baselen+1));
 -      write(fd, " = ", 3);
 +      /* Check to see if the value needs to be quoted. */
 +      if (value[0] == ' ')
 +              quote = 1;
 +      for (i = 0; value[i]; i++)
 +              if (value[i] == ';' || value[i] == '#')
 +                      quote = 1;
 +      if (value[i-1] == ' ')
 +              quote = 1;
 +
 +      if (write_in_full(fd, "\t", 1) != 1 ||
 +          write_in_full(fd, key+store.baselen+1, length) != length ||
 +          write_in_full(fd, " = ", 3) != 3)
 +              return 0;
 +      if (quote && write_in_full(fd, "\"", 1) != 1)
 +              return 0;
        for (i = 0; value[i]; i++)
                switch (value[i]) {
 -              case '\n': write(fd, "\\n", 2); break;
 -              case '\t': write(fd, "\\t", 2); break;
 -              case '"': case '\\': write(fd, "\\", 1);
 -              default: write(fd, value+i, 1);
 -      }
 -      write(fd, "\n", 1);
 +              case '\n':
 +                      if (write_in_full(fd, "\\n", 2) != 2)
 +                              return 0;
 +                      break;
 +              case '\t':
 +                      if (write_in_full(fd, "\\t", 2) != 2)
 +                              return 0;
 +                      break;
 +              case '"':
 +              case '\\':
 +                      if (write_in_full(fd, "\\", 1) != 1)
 +                              return 0;
 +              default:
 +                      if (write_in_full(fd, value+i, 1) != 1)
 +                              return 0;
 +                      break;
 +              }
 +      if (quote && write_in_full(fd, "\"", 1) != 1)
 +              return 0;
 +      if (write_in_full(fd, "\n", 1) != 1)
 +              return 0;
 +      return 1;
  }
  
  static int find_beginning_of_line(const char* contents, int size,
@@@ -693,10 -653,9 +698,10 @@@ int git_config_set_multivar(const char
                }
  
                store.key = (char*)key;
 -              store_write_section(fd, key);
 -              store_write_pair(fd, key, value);
 -      } else{
 +              if (!store_write_section(fd, key) ||
 +                  !store_write_pair(fd, key, value))
 +                      goto write_err_out;
 +      } else {
                struct stat st;
                char* contents;
                int i, copy_begin, copy_end, new_line = 0;
  
                        /* write the first part of the config */
                        if (copy_end > copy_begin) {
 -                              write(fd, contents + copy_begin,
 -                              copy_end - copy_begin);
 -                              if (new_line)
 -                                      write(fd, "\n", 1);
 +                              if (write_in_full(fd, contents + copy_begin,
 +                                                copy_end - copy_begin) <
 +                                  copy_end - copy_begin)
 +                                      goto write_err_out;
 +                              if (new_line &&
 +                                  write_in_full(fd, "\n", 1) != 1)
 +                                      goto write_err_out;
                        }
                        copy_begin = store.offset[i];
                }
  
                /* write the pair (value == NULL means unset) */
                if (value != NULL) {
 -                      if (store.state == START)
 -                              store_write_section(fd, key);
 -                      store_write_pair(fd, key, value);
 +                      if (store.state == START) {
 +                              if (!store_write_section(fd, key))
 +                                      goto write_err_out;
 +                      }
 +                      if (!store_write_pair(fd, key, value))
 +                              goto write_err_out;
                }
  
                /* write the rest of the config */
                if (copy_begin < st.st_size)
 -                      write(fd, contents + copy_begin,
 -                              st.st_size - copy_begin);
 +                      if (write_in_full(fd, contents + copy_begin,
 +                                        st.st_size - copy_begin) <
 +                          st.st_size - copy_begin)
 +                              goto write_err_out;
  
                munmap(contents, st.st_size);
                unlink(config_filename);
@@@ -824,11 -775,6 +829,11 @@@ out_free
                free(lock_file);
        }
        return ret;
 +
 +write_err_out:
 +      ret = write_error();
 +      goto out_free;
 +
  }
  
  int git_config_rename_section(const char *old_name, const char *new_name)
  
        while (fgets(buf, sizeof(buf), config_file)) {
                int i;
 +              int length;
                for (i = 0; buf[i] && isspace(buf[i]); i++)
                        ; /* do nothing */
                if (buf[i] == '[') {
                                /* old_name matches */
                                ret++;
                                store.baselen = strlen(new_name);
 -                              store_write_section(out_fd, new_name);
 +                              if (!store_write_section(out_fd, new_name)) {
 +                                      ret = write_error();
 +                                      goto out;
 +                              }
                                continue;
                        }
                }
 -              write(out_fd, buf, strlen(buf));
 +              length = strlen(buf);
 +              if (write_in_full(out_fd, buf, length) != length) {
 +                      ret = write_error();
 +                      goto out;
 +              }
        }
        fclose(config_file);
        if (close(out_fd) || commit_lock_file(lock) < 0)
 -              ret = error("Cannot commit config file!");
 +                      ret = error("Cannot commit config file!");
   out:
        free(config_filename);
        return ret;
diff --combined git-am.sh
index 59d663ba9e0c3828d11b442c6fd9536a87d937cb,f50de61049d039f939956dc4a8c0b502dc1d70e5..1252f26bbd46484f25e58e92680e553f7fd7c1da
+++ b/git-am.sh
@@@ -2,11 -2,12 +2,12 @@@
  #
  # Copyright (c) 2005, 2006 Junio C Hamano
  
 -USAGE='[--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way]
 +USAGE='[--signoff] [--dotest=<dir>] [--utf8 | --no-utf8] [--binary] [--3way]
    [--interactive] [--whitespace=<option>] <mbox>...
    or, when resuming [--skip | --resolved]'
  . git-sh-setup
  set_reflog_action am
+ require_work_tree
  
  git var GIT_COMMITTER_IDENT >/dev/null || exit
  
@@@ -105,7 -106,7 +106,7 @@@ It does not apply to blobs recorded in 
  }
  
  prec=4
 -dotest=.dotest sign= utf8= keep= skip= interactive= resolved= binary= ws= resolvemsg=
 +dotest=.dotest sign= utf8=t keep= skip= interactive= resolved= binary= ws= resolvemsg=
  
  while case "$#" in 0) break;; esac
  do
        -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
        sign=t; shift ;;
        -u|--u|--ut|--utf|--utf8)
 -      utf8=t; shift ;;
 +      utf8=t; shift ;; # this is now default
 +      --no-u|--no-ut|--no-utf|--no-utf8)
 +      utf8=; shift ;;
        -k|--k|--ke|--kee|--keep)
        keep=t; shift ;;
  
@@@ -228,8 -227,6 +229,8 @@@ f
  if test "$(cat "$dotest/utf8")" = t
  then
        utf8=-u
 +else
 +      utf8=-n
  fi
  if test "$(cat "$dotest/keep")" = t
  then
diff --combined git-checkout.sh
index 8f4356d49a4935ff4a238cad3d0f90760d3e1afd,a5649a0504f3d5b25fe800e85c0b3eb122368289..a2b8e4fa4aa3607ce4981c84b9c6f9d31a9dec97
@@@ -3,10 -3,10 +3,11 @@@
  USAGE='[-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
  SUBDIRECTORY_OK=Sometimes
  . git-sh-setup
+ require_work_tree
  
  old_name=HEAD
  old=$(git-rev-parse --verify $old_name 2>/dev/null)
 +oldbranch=$(git-symbolic-ref $old_name 2>/dev/null)
  new=
  new_name=
  force=
@@@ -14,8 -14,6 +15,8 @@@ branch
  newbranch=
  newbranch_log=
  merge=
 +LF='
 +'
  while [ "$#" != "0" ]; do
      arg="$1"
      shift
@@@ -53,7 -51,7 +54,7 @@@
                                exit 1
                        fi
                        new="$rev"
 -                      new_name="$arg^0"
 +                      new_name="$arg"
                        if git-show-ref --verify --quiet -- "refs/heads/$arg"
                        then
                                branch="$arg"
  
  [ -z "$new" ] && new=$old && new_name="$old_name"
  
 -# If we don't have an old branch that we're switching to,
 +# If we don't have an existing branch that we're switching to,
  # and we don't have a new branch name for the target we
 -# are switching to, then we'd better just be checking out
 -# what we already had
 +# are switching to, then we are detaching our HEAD from any
 +# branch.  However, if "git checkout HEAD" detaches the HEAD
 +# from the current branch, even though that may be logically
 +# correct, it feels somewhat funny.  More importantly, we do not
 +# want "git checkout" nor "git checkout -f" to detach HEAD.
  
 -[ -z "$branch$newbranch" ] &&
 -      [ "$new" != "$old" ] &&
 -      die "git checkout: provided reference cannot be checked out directly
 +detached=
 +detach_warn=
  
 -  You need -b to associate a new branch with the wanted checkout. Example:
 -  git checkout -b <new_branch_name> $arg
 -"
 +if test -z "$branch$newbranch" && test "$new" != "$old"
 +then
 +      detached="$new"
 +      if test -n "$oldbranch"
 +      then
 +              detach_warn="warning: you are not on ANY branch anymore.
 +If you meant to create a new branch from the commit, you need -b to
 +associate a new branch with the wanted checkout.  Example:
 +  git checkout -b <new_branch_name> $arg"
 +      fi
 +elif test -z "$oldbranch" && test -n "$branch"
 +then
 +      # Coming back...
 +      if test -z "$force"
 +      then
 +              git show-ref -d -s | grep "$old" >/dev/null || {
 +                      echo >&2 \
 +"You are not on any branch and switching to branch '$new_name'
 +may lose your changes.  At this point, you can do one of two things:
 + (1) Decide it is Ok and say 'git checkout -f $new_name';
 + (2) Start a new branch from the current commit, by saying
 +     'git checkout -b <branch-name>'.
 +Leaving your HEAD detached; not switching to branch '$new_name'."
 +                      exit 1;
 +              }
 +      fi
 +fi
  
  if [ "X$old" = X ]
  then
 -      echo "warning: You do not appear to currently be on a branch." >&2
 -      echo "warning: Forcing checkout of $new_name." >&2
 +      echo >&2 "warning: You appear to be on a branch yet to be born."
 +      echo >&2 "warning: Forcing checkout of $new_name."
        force=1
  fi
  
@@@ -255,25 -227,8 +256,25 @@@ if [ "$?" -eq 0 ]; the
                git-update-ref -m "checkout: Created from $new_name" "refs/heads/$newbranch" $new || exit
                branch="$newbranch"
        fi
 -      [ "$branch" ] &&
 -      GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
 +      if test -n "$branch"
 +      then
 +              GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
 +      elif test -n "$detached"
 +      then
 +              # NEEDSWORK: we would want a command to detach the HEAD
 +              # atomically, instead of this handcrafted command sequence.
 +              # Perhaps:
 +              #       git update-ref --detach HEAD $new
 +              # or something like that...
 +              #
 +              echo "$detached" >"$GIT_DIR/HEAD.new" &&
 +              mv "$GIT_DIR/HEAD.new" "$GIT_DIR/HEAD" ||
 +                      die "Cannot detach HEAD"
 +              if test -n "$detach_warn"
 +              then
 +                      echo >&2 "$detach_warn"
 +              fi
 +      fi
        rm -f "$GIT_DIR/MERGE_HEAD"
  else
        exit 1
diff --combined git-commit.sh
index c2beb76fe436279422ff5212aed573fb821bad7b,557b90355cdbaf108f0e339d61f7bf076cc7942d..eddd863015b4829fc833ba5bc064720eaa4245be
@@@ -6,6 -6,7 +6,7 @@@
  USAGE='[-a] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit>] [-u] [--amend] [-e] [--author <author>] [[-i | -o] <path>...]'
  SUBDIRECTORY_OK=Yes
  . git-sh-setup
+ require_work_tree
  
  git-rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
  
@@@ -628,7 -629,7 +629,7 @@@ the
        if test -z "$quiet"
        then
                echo "Created${initial_commit:+ initial} commit $commit"
 -              git-diff-tree --shortstat --summary --root --no-commit-id HEAD
 +              git-diff-tree --shortstat --summary --root --no-commit-id HEAD --
        fi
  fi
  
diff --combined git.c
index 9ce545d67693c8713b4254d5fa0e186723e348c2,692773b9aec2c68db6ae485b60bbc74a961f2cc9..72a1486f30a93c6822611c834a391bfc351c398f
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -199,6 -199,11 +199,11 @@@ const char git_version_string[] = GIT_V
  
  #define RUN_SETUP     (1<<0)
  #define USE_PAGER     (1<<1)
+ /*
+  * require working tree to be present -- anything uses this needs
+  * RUN_SETUP for reading from the configuration file.
+  */
+ #define NOT_BARE      (1<<2)
  
  static void handle_internal_command(int argc, const char **argv, char **envp)
  {
                int (*fn)(int, const char **, const char *);
                int option;
        } commands[] = {
-               { "add", cmd_add, RUN_SETUP },
+               { "add", cmd_add, RUN_SETUP | NOT_BARE },
                { "annotate", cmd_annotate, },
                { "apply", cmd_apply },
                { "archive", cmd_archive },
                { "cherry", cmd_cherry, RUN_SETUP },
                { "commit-tree", cmd_commit_tree, RUN_SETUP },
                { "count-objects", cmd_count_objects, RUN_SETUP },
 +              { "describe", cmd_describe, RUN_SETUP },
                { "diff", cmd_diff, RUN_SETUP | USE_PAGER },
                { "diff-files", cmd_diff_files, RUN_SETUP },
                { "diff-index", cmd_diff_index, RUN_SETUP },
                { "mailinfo", cmd_mailinfo },
                { "mailsplit", cmd_mailsplit },
                { "merge-file", cmd_merge_file },
-               { "mv", cmd_mv, RUN_SETUP },
+               { "mv", cmd_mv, RUN_SETUP | NOT_BARE },
                { "name-rev", cmd_name_rev, RUN_SETUP },
                { "pack-objects", cmd_pack_objects, RUN_SETUP },
                { "pickaxe", cmd_blame, RUN_SETUP | USE_PAGER },
                { "rerere", cmd_rerere, RUN_SETUP },
                { "rev-list", cmd_rev_list, RUN_SETUP },
                { "rev-parse", cmd_rev_parse, RUN_SETUP },
-               { "rm", cmd_rm, RUN_SETUP },
-               { "runstatus", cmd_runstatus, RUN_SETUP },
+               { "rm", cmd_rm, RUN_SETUP | NOT_BARE },
+               { "runstatus", cmd_runstatus, RUN_SETUP | NOT_BARE },
                { "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
                { "show-branch", cmd_show_branch, RUN_SETUP },
                { "show", cmd_show, RUN_SETUP | USE_PAGER },
                        prefix = setup_git_directory();
                if (p->option & USE_PAGER)
                        setup_pager();
+               if ((p->option & NOT_BARE) && is_bare_repository())
+                       die("%s cannot be used in a bare git directory", cmd);
                trace_argv_printf(argv, argc, "trace: built-in: git");
  
                exit(p->fn(argc, argv, prefix));
diff --combined refs.c
index d189d8ad99de2dd7a65a2b10dc2e353055c55509,499086ba6145fd988ba980ce35d47ff06d0bf69e..689ac50bae64a1068f2d9b1d720817748fc2289d
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -284,7 -284,7 +284,7 @@@ const char *resolve_ref(const char *ref
                fd = open(path, O_RDONLY);
                if (fd < 0)
                        return NULL;
 -              len = read(fd, buffer, sizeof(buffer)-1);
 +              len = read_in_full(fd, buffer, sizeof(buffer)-1);
                close(fd);
  
                /*
@@@ -332,7 -332,7 +332,7 @@@ int create_symref(const char *ref_targe
        }
        lockpath = mkpath("%s.lock", git_HEAD);
        fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666); 
 -      written = write(fd, ref, len);
 +      written = write_in_full(fd, ref, len);
        close(fd);
        if (written != len) {
                unlink(lockpath);
@@@ -923,6 -923,9 +923,9 @@@ static int log_ref_write(struct ref_loc
        char *logrec;
        const char *committer;
  
+       if (log_all_ref_updates < 0)
+               log_all_ref_updates = !is_bare_repository();
        if (log_all_ref_updates &&
            (!strncmp(lock->ref_name, "refs/heads/", 11) ||
             !strncmp(lock->ref_name, "refs/remotes/", 13))) {
                        sha1_to_hex(sha1),
                        committer);
        }
 -      written = len <= maxlen ? write(logfd, logrec, len) : -1;
 +      written = len <= maxlen ? write_in_full(logfd, logrec, len) : -1;
        free(logrec);
        close(logfd);
        if (written != len)
@@@ -987,8 -990,8 +990,8 @@@ int write_ref_sha1(struct ref_lock *loc
                unlock_ref(lock);
                return 0;
        }
 -      if (write(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||
 -          write(lock->lock_fd, &term, 1) != 1
 +      if (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||
 +          write_in_full(lock->lock_fd, &term, 1) != 1
                || close(lock->lock_fd) < 0) {
                error("Couldn't write %s", lock->lk->filename);
                unlock_ref(lock);
@@@ -1097,7 -1100,7 +1100,7 @@@ int read_ref_at(const char *ref, unsign
        return 0;
  }
  
 -void for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
 +int for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
  {
        const char *logfile;
        FILE *logfp;
        logfile = git_path("logs/%s", ref);
        logfp = fopen(logfile, "r");
        if (!logfp)
 -              return;
 +              return -1;
        while (fgets(buf, sizeof(buf), logfp)) {
                unsigned char osha1[20], nsha1[20];
 -              int len;
 +              char *email_end, *message;
 +              unsigned long timestamp;
 +              int len, ret, tz;
  
                /* old SP new SP name <email> SP time TAB msg LF */
                len = strlen(buf);
                if (len < 83 || buf[len-1] != '\n' ||
                    get_sha1_hex(buf, osha1) || buf[40] != ' ' ||
 -                  get_sha1_hex(buf + 41, nsha1) || buf[81] != ' ')
 +                  get_sha1_hex(buf + 41, nsha1) || buf[81] != ' ' ||
 +                  !(email_end = strchr(buf + 82, '>')) ||
 +                  email_end[1] != ' ' ||
 +                  !(timestamp = strtoul(email_end + 2, &message, 10)) ||
 +                  !message || message[0] != ' ' ||
 +                  (message[1] != '+' && message[1] != '-') ||
 +                  !isdigit(message[2]) || !isdigit(message[3]) ||
 +                  !isdigit(message[4]) || !isdigit(message[5]) ||
 +                  message[6] != '\t')
                        continue; /* corrupt? */
 -              fn(osha1, nsha1, buf+82, cb_data);
 +              email_end[1] = '\0';
 +              tz = strtol(message + 1, NULL, 10);
 +              message += 7;
 +              ret = fn(osha1, nsha1, buf+82, timestamp, tz, message, cb_data);
 +              if (ret)
 +                      return ret;
        }
        fclose(logfp);
 +      return 0;
  }