Add rm and strip abilities to atree.
The new line syntax is: [SRC] [rm|strip] DEST This allows one to write things like this in atree: bin/src bin/src bin/dest bin/src "bin/another file name" rm dest/file rm dest/dir # recursive strip bin/src bin/src strip bin/dest Src and dest can contain spaces if full enclosed in double-quotes. The strip command can be overridden using the STRIP env var. Change-Id: I22aae7a87c36c082e1aab87132099a3c644914da
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
@@ -10,7 +12,7 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
bool g_debug = false;
|
bool g_debug = getenv("ATREE_DEBUG") != NULL;
|
||||||
vector<string> g_listFiles;
|
vector<string> g_listFiles;
|
||||||
vector<string> g_inputBases;
|
vector<string> g_inputBases;
|
||||||
map<string, string> g_variables;
|
map<string, string> g_variables;
|
||||||
@@ -33,6 +35,7 @@ const char* USAGE =
|
|||||||
" -m DEPENDENCY Output a make-formatted file containing the list.\n"
|
" -m DEPENDENCY Output a make-formatted file containing the list.\n"
|
||||||
" of files included. It sets the variable ATREE_FILES.\n"
|
" of files included. It sets the variable ATREE_FILES.\n"
|
||||||
" -v VAR=VAL Replaces ${VAR} by VAL when reading input files.\n"
|
" -v VAR=VAL Replaces ${VAR} by VAL when reading input files.\n"
|
||||||
|
" -d Verbose debug mode.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"FILELIST file format:\n"
|
"FILELIST file format:\n"
|
||||||
" The FILELIST files contain the list of files that will end up\n"
|
" The FILELIST files contain the list of files that will end up\n"
|
||||||
@@ -42,11 +45,13 @@ const char* USAGE =
|
|||||||
" In a FILELIST file, comment lines start with a #. Other lines\n"
|
" In a FILELIST file, comment lines start with a #. Other lines\n"
|
||||||
" are of the format:\n"
|
" are of the format:\n"
|
||||||
"\n"
|
"\n"
|
||||||
" DEST\n"
|
" [rm|strip] DEST\n"
|
||||||
" SRC DEST\n"
|
" SRC [strip] DEST\n"
|
||||||
" -SRCPATTERN\n"
|
" -SRCPATTERN\n"
|
||||||
"\n"
|
"\n"
|
||||||
" DEST should be path relative to the output directory.\n"
|
" DEST should be path relative to the output directory.\n"
|
||||||
|
" 'rm DEST' removes the destination file and fails if it's missing.\n"
|
||||||
|
" 'strip DEST' strips the binary destination file.\n"
|
||||||
" If SRC is supplied, the file names can be different.\n"
|
" If SRC is supplied, the file names can be different.\n"
|
||||||
" SRCPATTERN is a pattern for the filenames.\n"
|
" SRCPATTERN is a pattern for the filenames.\n"
|
||||||
"\n";
|
"\n";
|
||||||
@@ -72,13 +77,26 @@ add_variable(const char* arg) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
debug_printf(const char* format, ...)
|
||||||
|
{
|
||||||
|
if (g_debug) {
|
||||||
|
fflush(stderr);
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
vprintf(format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char* const* argv)
|
main(int argc, char* const* argv)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
bool done = false;
|
bool done = false;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
int opt = getopt(argc, argv, "f:I:o:hlm:v:");
|
int opt = getopt(argc, argv, "f:I:o:hlm:v:d");
|
||||||
switch (opt)
|
switch (opt)
|
||||||
{
|
{
|
||||||
case -1:
|
case -1:
|
||||||
@@ -117,6 +135,9 @@ main(int argc, char* const* argv)
|
|||||||
return usage();
|
return usage();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'd':
|
||||||
|
g_debug = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
case '?':
|
case '?':
|
||||||
case 'h':
|
case 'h':
|
||||||
@@ -169,7 +190,7 @@ main(int argc, char* const* argv)
|
|||||||
|
|
||||||
// read file lists
|
// read file lists
|
||||||
for (vector<string>::iterator it=g_listFiles.begin();
|
for (vector<string>::iterator it=g_listFiles.begin();
|
||||||
it!=g_listFiles.end(); it++) {
|
it!=g_listFiles.end(); it++) {
|
||||||
err = read_list_file(*it, g_variables, &files, &excludes);
|
err = read_list_file(*it, g_variables, &files, &excludes);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return err;
|
return err;
|
||||||
@@ -181,7 +202,6 @@ main(int argc, char* const* argv)
|
|||||||
for (vector<FileRecord>::iterator it=files.begin();
|
for (vector<FileRecord>::iterator it=files.begin();
|
||||||
it!=files.end(); it++) {
|
it!=files.end(); it++) {
|
||||||
err |= locate(&(*it), g_inputBases);
|
err |= locate(&(*it), g_inputBases);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// expand the directories that we should copy into a list of files
|
// expand the directories that we should copy into a list of files
|
||||||
@@ -219,8 +239,8 @@ main(int argc, char* const* argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// gather files that should become directores and directories that should
|
// gather files that should become directores
|
||||||
// become files
|
// and directories that should become files
|
||||||
for (vector<FileRecord>::iterator it=files.begin();
|
for (vector<FileRecord>::iterator it=files.begin();
|
||||||
it!=files.end(); it++) {
|
it!=files.end(); it++) {
|
||||||
if (it->outMod != 0 && it->sourceIsDir != it->outIsDir) {
|
if (it->outMod != 0 && it->sourceIsDir != it->outIsDir) {
|
||||||
@@ -231,48 +251,66 @@ main(int argc, char* const* argv)
|
|||||||
// delete files
|
// delete files
|
||||||
for (set<string>::iterator it=deleted.begin();
|
for (set<string>::iterator it=deleted.begin();
|
||||||
it!=deleted.end(); it++) {
|
it!=deleted.end(); it++) {
|
||||||
if (g_debug) {
|
debug_printf("deleting %s\n", it->c_str());
|
||||||
printf("deleting %s\n", it->c_str());
|
|
||||||
}
|
|
||||||
err = remove_recursively(*it);
|
err = remove_recursively(*it);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove all files or directories as requested from the input atree file.
|
||||||
|
// must be done before create new directories.
|
||||||
|
for (vector<FileRecord>::iterator it=files.begin();
|
||||||
|
it!=files.end(); it++) {
|
||||||
|
if (!it->sourceIsDir) {
|
||||||
|
if (it->fileOp == FILE_OP_REMOVE &&
|
||||||
|
deleted.count(it->outPath) == 0) {
|
||||||
|
debug_printf("remove %s\n", it->outPath.c_str());
|
||||||
|
err = remove_recursively(it->outPath);
|
||||||
|
if (err != 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// make directories
|
// make directories
|
||||||
for (set<string>::iterator it=directories.begin();
|
for (set<string>::iterator it=directories.begin();
|
||||||
it!=directories.end(); it++) {
|
it!=directories.end(); it++) {
|
||||||
if (g_debug) {
|
debug_printf("mkdir %s\n", it->c_str());
|
||||||
printf("mkdir %s\n", it->c_str());
|
|
||||||
}
|
|
||||||
err = mkdir_recursively(*it);
|
err = mkdir_recursively(*it);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy (or link) files
|
// copy (or link) files that are newer or of different size
|
||||||
for (vector<FileRecord>::iterator it=files.begin();
|
for (vector<FileRecord>::iterator it=files.begin();
|
||||||
it!=files.end(); it++) {
|
it!=files.end(); it++) {
|
||||||
if (!it->sourceIsDir) {
|
if (!it->sourceIsDir) {
|
||||||
if (g_debug) {
|
if (it->fileOp == FILE_OP_REMOVE) {
|
||||||
printf("copy %s(%ld) ==> %s(%ld)", it->sourcePath.c_str(),
|
continue;
|
||||||
it->sourceMod, it->outPath.c_str(), it->outMod);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it->outMod < it->sourceMod) {
|
debug_printf("copy %s(%ld) ==> %s(%ld)",
|
||||||
|
it->sourcePath.c_str(), it->sourceMod,
|
||||||
|
it->outPath.c_str(), it->outMod);
|
||||||
|
|
||||||
|
if (it->outSize != it->sourceSize || it->outMod < it->sourceMod) {
|
||||||
err = copy_file(it->sourcePath, it->outPath);
|
err = copy_file(it->sourcePath, it->outPath);
|
||||||
if (g_debug) {
|
debug_printf(" done.\n");
|
||||||
printf(" done.\n");
|
|
||||||
}
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (g_debug) {
|
debug_printf(" skipping.\n");
|
||||||
printf(" skipping.\n");
|
}
|
||||||
|
|
||||||
|
if (it->fileOp == FILE_OP_STRIP) {
|
||||||
|
debug_printf("strip %s\n", it->outPath.c_str());
|
||||||
|
err = strip_file(it->outPath);
|
||||||
|
if (err != 0) {
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,7 +62,7 @@ void
|
|||||||
split_line(const char* p, vector<string>* out)
|
split_line(const char* p, vector<string>* out)
|
||||||
{
|
{
|
||||||
const char* q = p;
|
const char* q = p;
|
||||||
enum { WHITE, TEXT } state = WHITE;
|
enum { WHITE, TEXT, IN_QUOTE } state = WHITE;
|
||||||
while (*p) {
|
while (*p) {
|
||||||
if (*p == '#') {
|
if (*p == '#') {
|
||||||
break;
|
break;
|
||||||
@@ -73,13 +73,25 @@ split_line(const char* p, vector<string>* out)
|
|||||||
case WHITE:
|
case WHITE:
|
||||||
if (!isspace(*p)) {
|
if (!isspace(*p)) {
|
||||||
q = p;
|
q = p;
|
||||||
state = TEXT;
|
state = (*p == '"') ? IN_QUOTE : TEXT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case IN_QUOTE:
|
||||||
|
if (*p == '"') {
|
||||||
|
state = TEXT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// otherwise fall-through to TEXT case
|
||||||
case TEXT:
|
case TEXT:
|
||||||
if (isspace(*p)) {
|
if (state != IN_QUOTE && isspace(*p)) {
|
||||||
if (q != p) {
|
if (q != p) {
|
||||||
out->push_back(string(q, p-q));
|
const char* start = q;
|
||||||
|
size_t len = p-q;
|
||||||
|
if (len > 2 && *start == '"' && start[len - 1] == '"') {
|
||||||
|
start++;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
out->push_back(string(start, len));
|
||||||
}
|
}
|
||||||
state = WHITE;
|
state = WHITE;
|
||||||
}
|
}
|
||||||
@@ -88,17 +100,25 @@ split_line(const char* p, vector<string>* out)
|
|||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
if (state == TEXT) {
|
if (state == TEXT) {
|
||||||
out->push_back(string(q, p-q));
|
const char* start = q;
|
||||||
|
size_t len = p-q;
|
||||||
|
if (len > 2 && *start == '"' && start[len - 1] == '"') {
|
||||||
|
start++;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
out->push_back(string(start, len));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_file(vector<FileRecord>* files, const string& listFile, int listLine,
|
add_file(vector<FileRecord>* files, const FileOpType fileOp,
|
||||||
|
const string& listFile, int listLine,
|
||||||
const string& sourceName, const string& outName)
|
const string& sourceName, const string& outName)
|
||||||
{
|
{
|
||||||
FileRecord rec;
|
FileRecord rec;
|
||||||
rec.listFile = listFile;
|
rec.listFile = listFile;
|
||||||
rec.listLine = listLine;
|
rec.listLine = listLine;
|
||||||
|
rec.fileOp = fileOp;
|
||||||
rec.sourceName = sourceName;
|
rec.sourceName = sourceName;
|
||||||
rec.outName = outName;
|
rec.outName = outName;
|
||||||
files->push_back(rec);
|
files->push_back(rec);
|
||||||
@@ -245,35 +265,52 @@ read_list_file(const string& filename,
|
|||||||
}
|
}
|
||||||
printf("]\n");
|
printf("]\n");
|
||||||
#endif
|
#endif
|
||||||
|
FileOpType op = FILE_OP_COPY;
|
||||||
|
string paths[2];
|
||||||
|
int pcount = 0;
|
||||||
|
string errstr;
|
||||||
|
for (vector<string>::iterator it = words.begin(); it != words.end(); ++it) {
|
||||||
|
const string& word = *it;
|
||||||
|
if (word == "rm") {
|
||||||
|
if (op != FILE_OP_COPY) {
|
||||||
|
errstr = "Error: you can only specifiy 'rm' or 'strip' once per line.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op = FILE_OP_REMOVE;
|
||||||
|
} else if (word == "strip") {
|
||||||
|
if (op != FILE_OP_COPY) {
|
||||||
|
errstr = "Error: you can only specifiy 'rm' or 'strip' once per line.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op = FILE_OP_STRIP;
|
||||||
|
} else if (pcount < 2) {
|
||||||
|
bool error = false;
|
||||||
|
paths[pcount++] = replace_variables(word, variables, &error);
|
||||||
|
if (error) {
|
||||||
|
err = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errstr = "Error: More than 2 paths per line.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (words.size() == 1) {
|
if (pcount == 0 && !errstr.empty()) {
|
||||||
// pattern: DEST
|
errstr = "Error: No path found on line.";
|
||||||
bool error = false;
|
|
||||||
string w0 = replace_variables(words[0], variables, &error);
|
|
||||||
if (error) {
|
|
||||||
err = 1;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
add_file(files, filename, i+1, w0, w0);
|
|
||||||
}
|
}
|
||||||
else if (words.size() == 2) {
|
|
||||||
// pattern: SRC DEST
|
if (!errstr.empty()) {
|
||||||
bool error = false;
|
fprintf(stderr, "%s:%d: bad format: %s\n%s\nExpected: [SRC] [rm|strip] DEST\n",
|
||||||
string w0, w1;
|
filename.c_str(), i+1, p, errstr.c_str());
|
||||||
w0 = replace_variables(words[0], variables, &error);
|
|
||||||
if (!error) {
|
|
||||||
w1 = replace_variables(words[1], variables, &error);
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
err = 1;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
add_file(files, filename, i+1, w0, w1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "%s:%d: bad format: %s\n", filename.c_str(),
|
|
||||||
i+1, p);
|
|
||||||
err = 1;
|
err = 1;
|
||||||
|
} else {
|
||||||
|
if (pcount == 1) {
|
||||||
|
// pattern: [rm|strip] DEST
|
||||||
|
paths[1] = paths[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
add_file(files, op, filename, i+1, paths[0], paths[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p = q;
|
p = q;
|
||||||
@@ -293,6 +330,14 @@ cleanup:
|
|||||||
int
|
int
|
||||||
locate(FileRecord* rec, const vector<string>& search)
|
locate(FileRecord* rec, const vector<string>& search)
|
||||||
{
|
{
|
||||||
|
if (rec->fileOp == FILE_OP_REMOVE) {
|
||||||
|
// Don't touch source files when removing a destination.
|
||||||
|
rec->sourceMod = 0;
|
||||||
|
rec->sourceSize = 0;
|
||||||
|
rec->sourceIsDir = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
for (vector<string>::const_iterator it=search.begin();
|
for (vector<string>::const_iterator it=search.begin();
|
||||||
@@ -304,6 +349,7 @@ locate(FileRecord* rec, const vector<string>& search)
|
|||||||
rec->sourceBase = *it;
|
rec->sourceBase = *it;
|
||||||
rec->sourcePath = full;
|
rec->sourcePath = full;
|
||||||
rec->sourceMod = st.st_mtime;
|
rec->sourceMod = st.st_mtime;
|
||||||
|
rec->sourceSize = st.st_size;
|
||||||
rec->sourceIsDir = S_ISDIR(st.st_mode);
|
rec->sourceIsDir = S_ISDIR(st.st_mode);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -324,9 +370,11 @@ stat_out(const string& base, FileRecord* rec)
|
|||||||
err = stat(rec->outPath.c_str(), &st);
|
err = stat(rec->outPath.c_str(), &st);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
rec->outMod = st.st_mtime;
|
rec->outMod = st.st_mtime;
|
||||||
|
rec->outSize = st.st_size;
|
||||||
rec->outIsDir = S_ISDIR(st.st_mode);
|
rec->outIsDir = S_ISDIR(st.st_mode);
|
||||||
} else {
|
} else {
|
||||||
rec->outMod = 0;
|
rec->outMod = 0;
|
||||||
|
rec->outSize = 0;
|
||||||
rec->outIsDir = false;
|
rec->outIsDir = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -427,3 +475,8 @@ list_dir(const FileRecord& rec, const vector<string>& excludes,
|
|||||||
{
|
{
|
||||||
return list_dir("", rec, excludes, files);
|
return list_dir("", rec, excludes, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileRecord::FileRecord() {
|
||||||
|
fileOp = FILE_OP_COPY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -8,8 +8,16 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
enum FileOpType {
|
||||||
|
FILE_OP_COPY = 0,
|
||||||
|
FILE_OP_REMOVE,
|
||||||
|
FILE_OP_STRIP
|
||||||
|
};
|
||||||
|
|
||||||
struct FileRecord
|
struct FileRecord
|
||||||
{
|
{
|
||||||
|
FileRecord();
|
||||||
|
|
||||||
string listFile;
|
string listFile;
|
||||||
int listLine;
|
int listLine;
|
||||||
|
|
||||||
@@ -18,9 +26,12 @@ struct FileRecord
|
|||||||
string sourcePath;
|
string sourcePath;
|
||||||
bool sourceIsDir;
|
bool sourceIsDir;
|
||||||
time_t sourceMod;
|
time_t sourceMod;
|
||||||
|
off_t sourceSize;
|
||||||
|
FileOpType fileOp;
|
||||||
|
|
||||||
string outName;
|
string outName;
|
||||||
string outPath;
|
string outPath;
|
||||||
|
off_t outSize;
|
||||||
time_t outMod;
|
time_t outMod;
|
||||||
bool outIsDir;
|
bool outIsDir;
|
||||||
unsigned int mode;
|
unsigned int mode;
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -64,10 +66,10 @@ remove_recursively(const string& path)
|
|||||||
#ifdef HAVE_DIRENT_D_TYPE
|
#ifdef HAVE_DIRENT_D_TYPE
|
||||||
bool is_directory = (ent->d_type == DT_DIR);
|
bool is_directory = (ent->d_type == DT_DIR);
|
||||||
#else
|
#else
|
||||||
// If dirent.d_type is missing, then use stat instead
|
// If dirent.d_type is missing, then use stat instead
|
||||||
struct stat stat_buf;
|
struct stat stat_buf;
|
||||||
stat(full.c_str(), &stat_buf);
|
stat(full.c_str(), &stat_buf);
|
||||||
bool is_directory = S_ISDIR(stat_buf.st_mode);
|
bool is_directory = S_ISDIR(stat_buf.st_mode);
|
||||||
#endif
|
#endif
|
||||||
if (is_directory) {
|
if (is_directory) {
|
||||||
dirs.push_back(full);
|
dirs.push_back(full);
|
||||||
@@ -146,3 +148,27 @@ copy_file(const string& src, const string& dst)
|
|||||||
COPY_NO_DEREFERENCE | COPY_FORCE | COPY_PERMISSIONS);
|
COPY_NO_DEREFERENCE | COPY_FORCE | COPY_PERMISSIONS);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
strip_file(const string& path)
|
||||||
|
{
|
||||||
|
// Default strip command to run is "strip" unless overridden by the STRIP env var.
|
||||||
|
const char* strip_cmd = getenv("STRIP");
|
||||||
|
if (!strip_cmd || !strip_cmd[0]) {
|
||||||
|
strip_cmd = "strip";
|
||||||
|
}
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == -1) {
|
||||||
|
// Fork failed. errno should be set.
|
||||||
|
return -1;
|
||||||
|
} else if (pid == 0) {
|
||||||
|
// Exec in the child. Only returns if execve failed.
|
||||||
|
return execlp(strip_cmd, strip_cmd, path.c_str(), (char *)NULL);
|
||||||
|
} else {
|
||||||
|
// Wait for child pid and return its exit code.
|
||||||
|
int status;
|
||||||
|
waitpid(pid, &status, 0);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -8,5 +8,6 @@ using namespace std;
|
|||||||
int remove_recursively(const string& path);
|
int remove_recursively(const string& path);
|
||||||
int mkdir_recursively(const string& path);
|
int mkdir_recursively(const string& path);
|
||||||
int copy_file(const string& src, const string& dst);
|
int copy_file(const string& src, const string& dst);
|
||||||
|
int strip_file(const string& path);
|
||||||
|
|
||||||
#endif // FS_H
|
#endif // FS_H
|
||||||
|
Reference in New Issue
Block a user