diff --git a/Makefile b/Makefile index 199fbe8738..164dbcf734 100644 --- a/Makefile +++ b/Makefile @@ -260,7 +260,7 @@ LIB_OBJS = \ server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \ tag.o tree.o usage.o config.o environment.o ctype.o copy.o \ fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \ - write_or_die.o \ + write_or_die.o trace.o \ alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) BUILTIN_OBJS = \ @@ -514,7 +514,7 @@ ifdef NO_SETENV COMPAT_CFLAGS += -DNO_SETENV COMPAT_OBJS += compat/setenv.o endif -ifdef NO_SETENV +ifdef NO_UNSETENV COMPAT_CFLAGS += -DNO_UNSETENV COMPAT_OBJS += compat/unsetenv.o endif diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index ca0ebc2585..0c180b53a3 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -15,7 +15,7 @@ static const char unpack_usage[] = "git-unpack-objects [-n] [-q] < pack-file"; /* We always read in 4kB chunks. */ static unsigned char buffer[4096]; -static unsigned long offset, len, eof; +static unsigned long offset, len; static SHA_CTX ctx; /* @@ -26,8 +26,6 @@ static void * fill(int min) { if (min <= len) return buffer + offset; - if (eof) - die("unable to fill input"); if (min > sizeof(buffer)) die("cannot fill %d bytes", min); if (offset) { diff --git a/cache.h b/cache.h index 1ff2696456..df5d86fe40 100644 --- a/cache.h +++ b/cache.h @@ -401,6 +401,7 @@ extern char git_commit_encoding[MAX_ENCODING_LENGTH]; extern int copy_fd(int ifd, int ofd); 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); /* Finish off pack transfer receiving end */ extern int receive_unpack_pack(int fd[2], const char *me, int quiet, int); @@ -426,4 +427,9 @@ extern struct commit *alloc_commit_node(void); extern struct tag *alloc_tag_node(void); extern void alloc_report(void); +/* trace.c */ +extern int nfvasprintf(char **str, const char *fmt, va_list va); +extern void trace_printf(const char *format, ...); +extern void trace_argv_printf(const char **argv, int count, const char *format, ...); + #endif /* CACHE_H */ diff --git a/exec_cmd.c b/exec_cmd.c index e30936d72c..5d6a1247b4 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -97,26 +97,12 @@ int execv_git_cmd(const char **argv) tmp = argv[0]; argv[0] = git_command; - if (getenv("GIT_TRACE")) { - const char **p = argv; - fputs("trace: exec:", stderr); - while (*p) { - fputc(' ', stderr); - sq_quote_print(stderr, *p); - ++p; - } - putc('\n', stderr); - fflush(stderr); - } + trace_argv_printf(argv, -1, "trace: exec:"); /* execve() can only ever return if it fails */ execve(git_command, (char **)argv, environ); - if (getenv("GIT_TRACE")) { - fprintf(stderr, "trace: exec failed: %s\n", - strerror(errno)); - fflush(stderr); - } + trace_printf("trace: exec failed: %s\n", strerror(errno)); argv[0] = tmp; } diff --git a/fsck-objects.c b/fsck-objects.c index ae0ec8d039..24286de15d 100644 --- a/fsck-objects.c +++ b/fsck-objects.c @@ -425,8 +425,23 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1) static void get_default_heads(void) { for_each_ref(fsck_handle_ref); - if (!default_refs) - die("No default references"); + + /* + * Not having any default heads isn't really fatal, but + * it does mean that "--unreachable" no longer makes any + * sense (since in this case everything will obviously + * be unreachable by definition. + * + * Showing dangling objects is valid, though (as those + * dangling objects are likely lost heads). + * + * So we just print a warning about it, and clear the + * "show_unreachable" flag. + */ + if (!default_refs) { + error("No default references"); + show_unreachable = 0; + } } static void fsck_object_dir(const char *path) diff --git a/git-repack.sh b/git-repack.sh index 9da92fb061..584a7323ac 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -38,7 +38,7 @@ case ",$all_into_one," in pack_objects= # Redundancy check in all-into-one case is trivial. - existing=`cd "$PACKDIR" && \ + existing=`test -d "$PACKDIR" && cd "$PACKDIR" && \ find . -type f \( -name '*.pack' -o -name '*.idx' \) -print` ;; esac diff --git a/git.c b/git.c index bd07289d71..0c8cfa8d34 100644 --- a/git.c +++ b/git.c @@ -179,17 +179,9 @@ static int handle_alias(int *argcp, const char ***argv) if (!strcmp(alias_command, new_argv[0])) die("recursive alias: %s", alias_command); - if (getenv("GIT_TRACE")) { - int i; - fprintf(stderr, "trace: alias expansion: %s =>", - alias_command); - for (i = 0; i < count; ++i) { - fputc(' ', stderr); - sq_quote_print(stderr, new_argv[i]); - } - fputc('\n', stderr); - fflush(stderr); - } + trace_argv_printf(new_argv, count, + "trace: alias expansion: %s =>", + alias_command); new_argv = xrealloc(new_argv, sizeof(char*) * (count + *argcp + 1)); @@ -292,16 +284,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) prefix = setup_git_directory(); if (p->option & USE_PAGER) setup_pager(); - if (getenv("GIT_TRACE")) { - int j; - fprintf(stderr, "trace: built-in: git"); - for (j = 0; j < argc; ++j) { - fputc(' ', stderr); - sq_quote_print(stderr, argv[j]); - } - putc('\n', stderr); - fflush(stderr); - } + trace_argv_printf(argv, argc, "trace: built-in: git"); exit(p->fn(argc, argv, prefix)); } diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 9324d71ebe..0984e85623 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -152,7 +152,7 @@ sub feature_snapshot { our @diff_opts = ('-M'); # taken from git_commit our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; -require $GITWEB_CONFIG if -e $GITWEB_CONFIG; +do $GITWEB_CONFIG if -e $GITWEB_CONFIG; # version of the core git binary our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown"; @@ -1027,9 +1027,30 @@ sub parse_difftree_raw_line { } } # 'c512b523472485aef4fff9e57b229d9d243c967f' - #elsif ($line =~ m/^([0-9a-fA-F]{40})$/) { - # $res{'commit'} = $1; - #} + elsif ($line =~ m/^([0-9a-fA-F]{40})$/) { + $res{'commit'} = $1; + } + + return wantarray ? %res : \%res; +} + +# parse line of git-ls-tree output +sub parse_ls_tree_line ($;%) { + my $line = shift; + my %opts = @_; + my %res; + + #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c' + $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/; + + $res{'mode'} = $1; + $res{'type'} = $2; + $res{'hash'} = $3; + if ($opts{'-z'}) { + $res{'name'} = $4; + } else { + $res{'name'} = unquote($4); + } return wantarray ? %res : \%res; } @@ -1454,6 +1475,62 @@ sub git_print_simplified_log { -remove_title => $remove_title); } +# print tree entry (row of git_tree), but without encompassing element +sub git_print_tree_entry { + my ($t, $basedir, $hash_base, $have_blame) = @_; + + my %base_key = (); + $base_key{hash_base} = $hash_base if defined $hash_base; + + print "" . mode_str($t->{'mode'}) . "\n"; + if ($t->{'type'} eq "blob") { + print "" . + $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, + file_name=>"$basedir$t->{'name'}", %base_key), + -class => "list"}, esc_html($t->{'name'})) . + "\n" . + "" . + $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, + file_name=>"$basedir$t->{'name'}", %base_key)}, + "blob"); + if ($have_blame) { + print " | " . + $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'}, + file_name=>"$basedir$t->{'name'}", %base_key)}, + "blame"); + } + if (defined $hash_base) { + print " | " . + $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")}, + "history"); + } + print " | " . + $cgi->a({-href => href(action=>"blob_plain", + hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")}, + "raw") . + "\n"; + + } elsif ($t->{'type'} eq "tree") { + print "" . + $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, + file_name=>"$basedir$t->{'name'}", %base_key)}, + esc_html($t->{'name'})) . + "\n" . + "" . + $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, + file_name=>"$basedir$t->{'name'}", %base_key)}, + "tree"); + if (defined $hash_base) { + print " | " . + $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + file_name=>"$basedir$t->{'name'}")}, + "history"); + } + print "\n"; + } +} + ## ...................................................................... ## functions printing large fragments of HTML @@ -2492,14 +2569,13 @@ sub git_tree { my $refs = git_get_references(); my $ref = format_ref_marker($refs, $hash_base); git_header_html(); - my %base_key = (); my $base = ""; my $have_blame = gitweb_check_feature('blame'); if (defined $hash_base && (my %co = parse_commit($hash_base))) { - $base_key{hash_base} = $hash_base; git_print_page_nav('tree','', $hash_base); git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base); } else { + undef $hash_base; print "
\n"; print "

\n"; print "
$hash
\n"; @@ -2512,54 +2588,17 @@ sub git_tree { print "\n"; my $alternate = 0; foreach my $line (@entries) { - #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c' - $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/; - my $t_mode = $1; - my $t_type = $2; - my $t_hash = $3; - my $t_name = validate_input($4); + my %t = parse_ls_tree_line($line, -z => 1); + if ($alternate) { print "\n"; } else { print "\n"; } $alternate ^= 1; - print "\n"; - if ($t_type eq "blob") { - print "\n" . - "\n"; - } elsif ($t_type eq "tree") { - print "\n" . - "\n"; - } + + git_print_tree_entry(\%t, $base, $hash_base, $have_blame); + print "\n"; } print "
" . mode_str($t_mode) . "" . - $cgi->a({-href => href(action=>"blob", hash=>$t_hash, file_name=>"$base$t_name", %base_key), - -class => "list"}, esc_html($t_name)) . - "" . - $cgi->a({-href => href(action=>"blob", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, - "blob"); - if ($have_blame) { - print " | " . - $cgi->a({-href => href(action=>"blame", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, - "blame"); - } - print " | " . - $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, - hash=>$t_hash, file_name=>"$base$t_name")}, - "history") . - " | " . - $cgi->a({-href => href(action=>"blob_plain", - hash=>$t_hash, file_name=>"$base$t_name")}, - "raw") . - "" . - $cgi->a({-href => href(action=>"tree", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, - esc_html($t_name)) . - "" . - $cgi->a({-href => href(action=>"tree", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, - "tree") . - " | " . - $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, file_name=>"$base$t_name")}, - "history") . - "
\n" . @@ -2778,10 +2817,6 @@ sub git_blobdiff { @difftree or die_error('404 Not Found', "Blob diff not found"); - } elsif (defined $hash) { # try to find filename from $hash - if ($hash !~ /[0-9a-fA-F]{40}/) { - $hash = git_to_hash($hash); - } } elsif (defined $hash && $hash =~ /[0-9a-fA-F]{40}/) { # try to find filename from $hash diff --git a/imap-send.c b/imap-send.c index 65c71c602d..6a52dbdca4 100644 --- a/imap-send.c +++ b/imap-send.c @@ -110,7 +110,6 @@ static char *next_arg( char ** ); static void free_generic_messages( message_t * ); -static int nfvasprintf( char **str, const char *fmt, va_list va ); static int nfsnprintf( char *buf, int blen, const char *fmt, ... ); @@ -371,21 +370,6 @@ free_generic_messages( message_t *msgs ) } } -static int -git_vasprintf( char **strp, const char *fmt, va_list ap ) -{ - int len; - char tmp[1024]; - - if ((len = vsnprintf( tmp, sizeof(tmp), fmt, ap )) < 0 || !(*strp = xmalloc( len + 1 ))) - return -1; - if (len >= (int)sizeof(tmp)) - vsprintf( *strp, fmt, ap ); - else - memcpy( *strp, tmp, len + 1 ); - return len; -} - static int nfsnprintf( char *buf, int blen, const char *fmt, ... ) { @@ -399,15 +383,6 @@ nfsnprintf( char *buf, int blen, const char *fmt, ... ) return ret; } -static int -nfvasprintf( char **str, const char *fmt, va_list va ) -{ - int ret = git_vasprintf( str, fmt, va ); - if (ret < 0) - die( "Fatal: Out of memory\n"); - return ret; -} - static struct { unsigned char i, j, s[256]; } rs; diff --git a/log-tree.c b/log-tree.c index 54cdaa4d81..fbe139920a 100644 --- a/log-tree.c +++ b/log-tree.c @@ -12,10 +12,58 @@ static void show_parents(struct commit *commit, int abbrev) } } +/* + * Search for "^[-A-Za-z]+: [^@]+@" pattern. It usually matches + * Signed-off-by: and Acked-by: lines. + */ +static int detect_any_signoff(char *letter, int size) +{ + char ch, *cp; + int seen_colon = 0; + int seen_at = 0; + int seen_name = 0; + int seen_head = 0; + + cp = letter + size; + while (letter <= --cp && (ch = *cp) == '\n') + continue; + + while (letter <= cp) { + ch = *cp--; + if (ch == '\n') + break; + + if (!seen_at) { + if (ch == '@') + seen_at = 1; + continue; + } + if (!seen_colon) { + if (ch == '@') + return 0; + else if (ch == ':') + seen_colon = 1; + else + seen_name = 1; + continue; + } + if (('A' <= ch && ch <= 'Z') || + ('a' <= ch && ch <= 'z') || + ch == '-') { + seen_head = 1; + continue; + } + /* no empty last line doesn't match */ + return 0; + } + return seen_head && seen_name; +} + static int append_signoff(char *buf, int buf_sz, int at, const char *signoff) { - int signoff_len = strlen(signoff); static const char signed_off_by[] = "Signed-off-by: "; + int signoff_len = strlen(signoff); + int has_signoff = 0; char *cp = buf; /* Do we have enough space to add it? */ @@ -23,58 +71,26 @@ static int append_signoff(char *buf, int buf_sz, int at, const char *signoff) return at; /* First see if we already have the sign-off by the signer */ - while (1) { - cp = strstr(cp, signed_off_by); - if (!cp) - break; + while ((cp = strstr(cp, signed_off_by))) { + + has_signoff = 1; + cp += strlen(signed_off_by); - if ((cp + signoff_len < buf + at) && - !strncmp(cp, signoff, signoff_len) && - isspace(cp[signoff_len])) - return at; /* we already have him */ + if (cp + signoff_len >= buf + at) + break; + if (strncmp(cp, signoff, signoff_len)) + continue; + if (!isspace(cp[signoff_len])) + continue; + /* we already have him */ + return at; } - /* Does the last line already end with "^[-A-Za-z]+: [^@]+@"? - * If not, add a blank line to separate the message from - * the run of Signed-off-by: and Acked-by: lines. - */ - { - char ch; - int seen_colon, seen_at, seen_name, seen_head, not_signoff; - seen_colon = 0; - seen_at = 0; - seen_name = 0; - seen_head = 0; - not_signoff = 0; - cp = buf + at; - while (buf <= --cp && (ch = *cp) == '\n') - ; - while (!not_signoff && buf <= cp && (ch = *cp--) != '\n') { - if (!seen_at) { - if (ch == '@') - seen_at = 1; - continue; - } - if (!seen_colon) { - if (ch == '@') - not_signoff = 1; - else if (ch == ':') - seen_colon = 1; - else - seen_name = 1; - continue; - } - if (('A' <= ch && ch <= 'Z') || - ('a' <= ch && ch <= 'z') || - ch == '-') { - seen_head = 1; - continue; - } - not_signoff = 1; - } - if (not_signoff || !seen_head || !seen_name) - buf[at++] = '\n'; - } + if (!has_signoff) + has_signoff = detect_any_signoff(buf, at); + + if (!has_signoff) + buf[at++] = '\n'; strcpy(buf + at, signed_off_by); at += strlen(signed_off_by); diff --git a/peek-remote.c b/peek-remote.c index 2b30980b04..87f1543fec 100644 --- a/peek-remote.c +++ b/peek-remote.c @@ -1,7 +1,6 @@ #include "cache.h" #include "refs.h" #include "pkt-line.h" -#include static const char peek_remote_usage[] = "git-peek-remote [--exec=upload-pack] [host:]directory"; diff --git a/quote.c b/quote.c index e220dcc280..a38786c177 100644 --- a/quote.c +++ b/quote.c @@ -74,6 +74,38 @@ char *sq_quote(const char *src) return buf; } +char *sq_quote_argv(const char** argv, int count) +{ + char *buf, *to; + int i; + size_t len = 0; + + /* Count argv if needed. */ + if (count < 0) { + for (count = 0; argv[count]; count++) + ; /* just counting */ + } + + /* Special case: no argv. */ + if (!count) + return xcalloc(1,1); + + /* Get destination buffer length. */ + for (i = 0; i < count; i++) + len += sq_quote_buf(NULL, 0, argv[i]) + 1; + + /* Alloc destination buffer. */ + to = buf = xmalloc(len + 1); + + /* Copy into destination buffer. */ + for (i = 0; i < count; ++i) { + *to++ = ' '; + to += sq_quote_buf(to, len, argv[i]); + } + + return buf; +} + char *sq_dequote(char *arg) { char *dst = arg; diff --git a/quote.h b/quote.h index fc5481e78a..a6c4611c25 100644 --- a/quote.h +++ b/quote.h @@ -31,6 +31,7 @@ extern char *sq_quote(const char *src); extern void sq_quote_print(FILE *stream, const char *src); extern size_t sq_quote_buf(char *dst, size_t n, const char *src); +extern char *sq_quote_argv(const char** argv, int count); /* This unwraps what sq_quote() produces in place, but returns * NULL if the input does not look like what sq_quote would have diff --git a/receive-pack.c b/receive-pack.c index 201531626c..78f75da5ca 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -2,7 +2,6 @@ #include "refs.h" #include "pkt-line.h" #include "run-command.h" -#include static const char receive_pack_usage[] = "git-receive-pack "; diff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh index 2e1b48a89b..b9f6d96363 100755 --- a/t/t5710-info-alternate.sh +++ b/t/t5710-info-alternate.sh @@ -58,6 +58,8 @@ test_expect_failure 'creating too deep nesting' \ git clone -l -s D E && git clone -l -s E F && git clone -l -s F G && +git clone -l -s G H && +cd H && test_valid_repo' cd "$base_dir" diff --git a/t/test-lib.sh b/t/test-lib.sh index b6d119af95..695243efad 100755 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -28,7 +28,6 @@ unset GIT_DIR unset GIT_EXTERNAL_DIFF unset GIT_INDEX_FILE unset GIT_OBJECT_DIRECTORY -unset GIT_TRACE unset SHA1_FILE_DIRECTORIES unset SHA1_FILE_DIRECTORY export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME diff --git a/trace.c b/trace.c new file mode 100644 index 0000000000..90847c3fd8 --- /dev/null +++ b/trace.c @@ -0,0 +1,125 @@ +/* + * GIT - The information manager from hell + * + * Copyright (C) 2000-2002 Michael R. Elkins + * Copyright (C) 2002-2004 Oswald Buddenhagen + * Copyright (C) 2004 Theodore Y. Ts'o + * Copyright (C) 2006 Mike McCormack + * Copyright (C) 2006 Christian Couder + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "cache.h" +#include "quote.h" + +/* Stolen from "imap-send.c". */ +static int git_vasprintf(char **strp, const char *fmt, va_list ap) +{ + int len; + char tmp[1024]; + + if ((len = vsnprintf(tmp, sizeof(tmp), fmt, ap)) < 0 || + !(*strp = xmalloc(len + 1))) + return -1; + if (len >= (int)sizeof(tmp)) + vsprintf(*strp, fmt, ap); + else + memcpy(*strp, tmp, len + 1); + return len; +} + +/* Stolen from "imap-send.c". */ +int nfvasprintf(char **str, const char *fmt, va_list va) +{ + int ret = git_vasprintf(str, fmt, va); + if (ret < 0) + die("Fatal: Out of memory\n"); + return ret; +} + +/* Get a trace file descriptor from GIT_TRACE env variable. */ +static int get_trace_fd() +{ + char *trace = getenv("GIT_TRACE"); + + if (!trace || !strcmp(trace, "0") || !strcasecmp(trace," false")) + return 0; + if (!strcmp(trace, "1") || !strcasecmp(trace, "true")) + return STDERR_FILENO; + if (strlen(trace) == 1 && isdigit(*trace)) + return atoi(trace); + + fprintf(stderr, "What does '%s' for GIT_TRACE means ?\n", trace); + fprintf(stderr, "Defaulting to tracing on stderr...\n"); + return STDERR_FILENO; +} + +static const char err_msg[] = "Could not trace into fd given by " + "GIT_TRACE environment variable"; + +void trace_printf(const char *format, ...) +{ + char *trace_str; + va_list rest; + int fd = get_trace_fd(); + + if (!fd) + return; + + va_start(rest, format); + nfvasprintf(&trace_str, format, rest); + va_end(rest); + + write_or_whine(fd, trace_str, strlen(trace_str), err_msg); + + free(trace_str); +} + +void trace_argv_printf(const char **argv, int count, const char *format, ...) +{ + char *argv_str, *format_str, *trace_str; + size_t argv_len, format_len, trace_len; + va_list rest; + int fd = get_trace_fd(); + + if (!fd) + return; + + /* Get the argv string. */ + argv_str = sq_quote_argv(argv, count); + argv_len = strlen(argv_str); + + /* Get the formated string. */ + va_start(rest, format); + nfvasprintf(&format_str, format, rest); + va_end(rest); + + /* Allocate buffer for trace string. */ + format_len = strlen(format_str); + trace_len = argv_len + format_len + 1; /* + 1 for \n */ + trace_str = xmalloc(trace_len + 1); + + /* Copy everything into the trace string. */ + strncpy(trace_str, format_str, format_len); + strncpy(trace_str + format_len, argv_str, argv_len); + strcpy(trace_str + trace_len - 1, "\n"); + + write_or_whine(fd, trace_str, trace_len, err_msg); + + free(argv_str); + free(format_str); + free(trace_str); +} diff --git a/write_or_die.c b/write_or_die.c index ab4cb8a69c..bfe4eeb649 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -18,3 +18,28 @@ void write_or_die(int fd, const void *buf, size_t count) p += written; } } + +int write_or_whine(int fd, const void *buf, size_t count, const char *msg) +{ + const char *p = buf; + ssize_t written; + + while (count > 0) { + written = xwrite(fd, p, count); + if (written == 0) { + fprintf(stderr, "%s: disk full?\n", msg); + return 0; + } + else if (written < 0) { + if (errno == EPIPE) + exit(0); + fprintf(stderr, "%s: write error (%s)\n", + msg, strerror(errno)); + return 0; + } + count -= written; + p += written; + } + + return 1; +}