##// END OF EJS Templates
export: add -B option to select a bookmark...
export: add -B option to select a bookmark Just like `hg email -B`, `hg strip -B`, supports -B in export to select a list of changesets reachable from a bookmark.

File last commit:

r35977:9724f549 default
r38035:c76526d7 default
Show More
util.c
200 lines | 4.2 KiB | text/x-c | CLexer
Yuya Nishihara
chg: import frontend sources...
r28060 /*
* Utility functions
*
* Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2 or any later version.
*/
Jun Wu
chg: add util function abortmsgerrno to print error with errno...
r28788 #include <errno.h>
Jun Wu
chg: extract the logic of setting FD_CLOEXEC to a utility function...
r28855 #include <fcntl.h>
Yuya Nishihara
chg: import frontend sources...
r28060 #include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
Yuya Nishihara
chg: initialize sigaction fields more reliably...
r28084 #include <string.h>
Jun Wu
chg: show timestamp with debug messages...
r34310 #include <sys/time.h>
Yuya Nishihara
chg: import frontend sources...
r28060 #include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "util.h"
Jun Wu
chg: use color in debug/error messages conditionally...
r28787 static int colorenabled = 0;
static inline void fsetcolor(FILE *fp, const char *code)
{
if (!colorenabled)
return;
fprintf(fp, "\033[%sm", code);
}
Jun Wu
chg: add util function abortmsgerrno to print error with errno...
r28788 static void vabortmsgerrno(int no, const char *fmt, va_list args)
{
fsetcolor(stderr, "1;31");
fputs("chg: abort: ", stderr);
vfprintf(stderr, fmt, args);
if (no != 0)
fprintf(stderr, " (errno = %d, %s)", no, strerror(no));
fsetcolor(stderr, "");
fputc('\n', stderr);
exit(255);
}
Yuya Nishihara
chg: import frontend sources...
r28060 void abortmsg(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
Jun Wu
chg: add util function abortmsgerrno to print error with errno...
r28788 vabortmsgerrno(0, fmt, args);
Yuya Nishihara
chg: import frontend sources...
r28060 va_end(args);
Jun Wu
chg: add util function abortmsgerrno to print error with errno...
r28788 }
Yuya Nishihara
chg: import frontend sources...
r28060
Jun Wu
chg: add util function abortmsgerrno to print error with errno...
r28788 void abortmsgerrno(const char *fmt, ...)
{
int no = errno;
va_list args;
va_start(args, fmt);
vabortmsgerrno(no, fmt, args);
va_end(args);
Yuya Nishihara
chg: import frontend sources...
r28060 }
static int debugmsgenabled = 0;
Jun Wu
chg: show timestamp with debug messages...
r34310 static double debugstart = 0;
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 static double now()
{
Jun Wu
chg: show timestamp with debug messages...
r34310 struct timeval t;
gettimeofday(&t, NULL);
return t.tv_usec / 1e6 + t.tv_sec;
}
Yuya Nishihara
chg: import frontend sources...
r28060
Jun Wu
chg: use color in debug/error messages conditionally...
r28787 void enablecolor(void)
{
colorenabled = 1;
}
Yuya Nishihara
chg: import frontend sources...
r28060 void enabledebugmsg(void)
{
debugmsgenabled = 1;
Jun Wu
chg: show timestamp with debug messages...
r34310 debugstart = now();
Yuya Nishihara
chg: import frontend sources...
r28060 }
void debugmsg(const char *fmt, ...)
{
if (!debugmsgenabled)
return;
va_list args;
va_start(args, fmt);
Jun Wu
chg: use color in debug/error messages conditionally...
r28787 fsetcolor(stderr, "1;30");
Jun Wu
chg: show timestamp with debug messages...
r34310 fprintf(stderr, "chg: debug: %4.6f ", now() - debugstart);
Yuya Nishihara
chg: import frontend sources...
r28060 vfprintf(stderr, fmt, args);
Jun Wu
chg: use color in debug/error messages conditionally...
r28787 fsetcolor(stderr, "");
fputc('\n', stderr);
Yuya Nishihara
chg: import frontend sources...
r28060 va_end(args);
}
Jun Wu
chg: add fchdirx as a utility function...
r28854 void fchdirx(int dirfd)
{
int r = fchdir(dirfd);
if (r == -1)
abortmsgerrno("failed to fchdir");
}
Jun Wu
chg: extract the logic of setting FD_CLOEXEC to a utility function...
r28855 void fsetcloexec(int fd)
{
int flags = fcntl(fd, F_GETFD);
if (flags < 0)
abortmsgerrno("cannot get flags of fd %d", fd);
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
abortmsgerrno("cannot set flags of fd %d", fd);
}
Jun Wu
chg: add utility functions mallocx, reallocx...
r28165 void *mallocx(size_t size)
{
void *result = malloc(size);
if (!result)
abortmsg("failed to malloc");
return result;
}
void *reallocx(void *ptr, size_t size)
{
void *result = realloc(ptr, size);
if (!result)
abortmsg("failed to realloc");
return result;
}
Yuya Nishihara
chg: import frontend sources...
r28060 /*
* Execute a shell command in mostly the same manner as system(), with the
* give environment variables, after chdir to the given cwd. Returns a status
* code compatible with the Python subprocess module.
*/
int runshellcmd(const char *cmd, const char *envp[], const char *cwd)
{
enum { F_SIGINT = 1, F_SIGQUIT = 2, F_SIGMASK = 4, F_WAITPID = 8 };
unsigned int doneflags = 0;
int status = 0;
struct sigaction newsa, oldsaint, oldsaquit;
sigset_t oldmask;
/* block or mask signals just as system() does */
Yuya Nishihara
chg: initialize sigaction fields more reliably...
r28084 memset(&newsa, 0, sizeof(newsa));
Yuya Nishihara
chg: import frontend sources...
r28060 newsa.sa_handler = SIG_IGN;
newsa.sa_flags = 0;
if (sigemptyset(&newsa.sa_mask) < 0)
goto done;
if (sigaction(SIGINT, &newsa, &oldsaint) < 0)
goto done;
doneflags |= F_SIGINT;
if (sigaction(SIGQUIT, &newsa, &oldsaquit) < 0)
goto done;
doneflags |= F_SIGQUIT;
if (sigaddset(&newsa.sa_mask, SIGCHLD) < 0)
goto done;
if (sigprocmask(SIG_BLOCK, &newsa.sa_mask, &oldmask) < 0)
goto done;
doneflags |= F_SIGMASK;
pid_t pid = fork();
if (pid < 0)
goto done;
if (pid == 0) {
sigaction(SIGINT, &oldsaint, NULL);
sigaction(SIGQUIT, &oldsaquit, NULL);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
if (cwd && chdir(cwd) < 0)
_exit(127);
const char *argv[] = {"sh", "-c", cmd, NULL};
if (envp) {
execve("/bin/sh", (char **)argv, (char **)envp);
} else {
execv("/bin/sh", (char **)argv);
}
_exit(127);
} else {
if (waitpid(pid, &status, 0) < 0)
goto done;
doneflags |= F_WAITPID;
}
done:
if (doneflags & F_SIGINT)
sigaction(SIGINT, &oldsaint, NULL);
if (doneflags & F_SIGQUIT)
sigaction(SIGQUIT, &oldsaquit, NULL);
if (doneflags & F_SIGMASK)
sigprocmask(SIG_SETMASK, &oldmask, NULL);
/* no way to report other errors, use 127 (= shell termination) */
if (!(doneflags & F_WAITPID))
return 127;
if (WIFEXITED(status))
return WEXITSTATUS(status);
if (WIFSIGNALED(status))
return -WTERMSIG(status);
return 127;
}