--- a/src/utils/pxattr.cpp
+++ b/src/utils/pxattr.cpp
@@ -509,6 +509,8 @@
#else // TEST_PXATTR Testing / driver ->
+#include "pxattr.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -516,16 +518,34 @@
#include <errno.h>
#include <string.h>
#include <ftw.h>
+#include <sys/types.h>
+#include <regex.h>
#include <iostream>
#include <fstream>
#include <map>
#include <algorithm>
#include <string>
+
using namespace std;
-#include "pxattr.h"
-
+
+static int antiverbose;
+
+static void printsyserr(const string& msg)
+{
+ if (antiverbose >= 2)
+ return;
+ cerr << msg << " " << strerror(errno) << endl;
+}
+
+#define message(X) \
+ { \
+ if (antiverbose == 0) { \
+ cout << X; \
+ } \
+ }
+
static void dotests();
// \-quote character c in input \ -> \\, nl -> \n cr -> \rc -> \c
@@ -590,19 +610,21 @@
}
return string::npos;
}
+
static const string PATH_START("Path: ");
-static void listattrs(const string& path)
+static bool listattrs(const string& path)
{
vector<string> names;
if (!pxattr::list(path, &names)) {
if (errno == ENOENT) {
- return;
- }
- perror("pxattr::list");
+ return false;
+ }
+ printsyserr("pxattr::list");
exit(1);
}
- if (names.empty())
- return;
+ if (names.empty()) {
+ return true;
+ }
// Sorting the names would not be necessary but it makes easier comparing
// backups
@@ -610,30 +632,56 @@
string quoted;
quote(path, quoted, 0);
- cout << PATH_START << quoted << endl;
+ message(PATH_START << quoted << endl);
for (vector<string>::const_iterator it = names.begin();
it != names.end(); it++) {
string value;
if (!pxattr::get(path, *it, &value)) {
if (errno == ENOENT) {
- return;
+ return false;
}
- perror("pxattr::get");
+ printsyserr("pxattr::get");
exit(1);
}
quote(*it, quoted, '=');
- cout << " " << quoted << "=";
+ message(" " << quoted << "=");
quote(value, quoted, 0);
- cout << quoted << endl;
- }
-}
-
-void setxattr(const string& path, const string& name, const string& value)
+ message(quoted << endl);
+ }
+ return true;
+}
+
+bool setxattr(const string& path, const string& name, const string& value)
{
if (!pxattr::set(path, name, value)) {
- perror("pxattr::set");
- exit(1);
- }
+ printsyserr("pxattr::set");
+ return false;
+ }
+ return true;
+}
+
+bool printxattr(const string &path, const string& name)
+{
+ string value;
+ if (!pxattr::get(path, name, &value)) {
+ if (errno == ENOENT) {
+ return false;
+ }
+ printsyserr("pxattr::get");
+ return false;
+ }
+ message(PATH_START << path << endl);
+ message(" " << name << " => " << value << endl);
+ return true;
+}
+
+bool delxattr(const string &path, const string& name)
+{
+ if (pxattr::del(path, name) < 0) {
+ printsyserr("pxattr::del");
+ return false;
+ }
+ return true;
}
// Restore xattrs stored in file created by pxattr -lR output
@@ -665,8 +713,8 @@
linenum++;
}
- // cout << "Got line " << linenum << " : [" << line << "] done " <<
- // done << endl;
+ // message("Got line " << linenum << " : [" << line << "] done " <<
+ // done << endl);
if (line.find(PATH_START) == 0 || done) {
if (!path.empty() && !attrs.empty()) {
@@ -702,38 +750,18 @@
}
}
-void printxattr(const string &path, const string& name)
-{
- cout << "Path: " << path << endl;
- string value;
- if (!pxattr::get(path, name, &value)) {
- if (errno == ENOENT) {
- return;
- }
- perror("pxattr::get");
- exit(1);
- }
- cout << " " << name << " => " << value << endl;
-}
-
-void delxattr(const string &path, const string& name)
-{
- if (pxattr::del(path, name) < 0) {
- perror("pxattr::del");
- exit(1);
- }
-}
-
static char *thisprog;
static char usage [] =
-"pxattr [-h] -n name pathname [...] : show value for name\n"
-"pxattr [-h] -n name -v value pathname [...] : add/replace attribute\n"
-"pxattr [-h] -x name pathname [...] : delete attribute\n"
-"pxattr [-h] [-l] [-R] pathname [...] : list attribute names and values\n"
+"pxattr [-hs] -n name pathname [...] : show value for name\n"
+"pxattr [-hs] -n name -r regexp pathname [...] : test value against regexp\n"
+"pxattr [-hs] -n name -v value pathname [...] : add/replace attribute\n"
+"pxattr [-hs] -x name pathname [...] : delete attribute\n"
+"pxattr [-hs] [-l] [-R] pathname [...] : list attribute names and values\n"
+" For all the options above, if no pathname arguments are given, pxattr\n"
+" will read file names on stdin, one per line.\n"
" [-h] : don't follow symbolic links (act on link itself)\n"
" [-R] : recursive listing. Args should be directory(ies)\n"
-" For all the options above, if no pathname arguments are given, pxattr\n"
-" will read file names on stdin, one per line.\n"
+" [-s] : be silent. With one option stdout is suppressed, with 2 stderr too\n"
"pxattr -S <backupfile> Restore xattrs from file created by pxattr -lR output\n"
" if backupfile is 'stdin', reads from stdin\n"
"pxattr -T: run tests on temp file in current directory"
@@ -748,40 +776,76 @@
static int op_flags;
#define OPT_MOINS 0x1
-#define OPT_n 0x2
-#define OPT_v 0x4
-#define OPT_h 0x8
-#define OPT_x 0x10
-#define OPT_l 0x20
-#define OPT_T 0x40
-#define OPT_R 0x80
-#define OPT_S 0x100
-
+#define OPT_h 0x2
+#define OPT_l 0x4
+#define OPT_n 0x8
+#define OPT_r 0x10
+#define OPT_R 0x20
+#define OPT_S 0x40
+#define OPT_T 0x80
+#define OPT_s 0x100
+#define OPT_v 0x200
+#define OPT_x 0x400
+
+// Static values for ftw
static string name, value;
-int processfile(const char* fn, const struct stat *sb, int typeflag)
-{
- //cout << "processfile " << fn << " opflags " << op_flags << endl;
+bool regex_test(const char *path, regex_t *preg)
+{
+ string value;
+ if (!pxattr::get(path, name, &value)) {
+ if (errno == ENOENT) {
+ return false;
+ }
+ printsyserr("pxattr::get");
+ return false;
+ }
+
+ int ret = regexec(preg, value.c_str(), 0, 0, 0);
+ if (ret == 0) {
+ message(path << endl);
+ return true;
+ } else if (ret == REG_NOMATCH) {
+ return false;
+ } else {
+ char errmsg[200];
+ regerror(ret, preg, errmsg, 200);
+ errno = 0;
+ printsyserr("regexec");
+ return false;
+ }
+}
+
+bool processfile(const char* fn, const struct stat *, int)
+{
+ //message("processfile " << fn << " opflags " << op_flags << endl);
if (op_flags & OPT_l) {
- listattrs(fn);
+ return listattrs(fn);
} else if (op_flags & OPT_n) {
if (op_flags & OPT_v) {
- setxattr(fn, name, value);
- } else {
- printxattr(fn, name);
+ return setxattr(fn, name, value);
+ } else {
+ return printxattr(fn, name);
}
} else if (op_flags & OPT_x) {
- delxattr(fn, name);
- }
+ return delxattr(fn, name);
+ }
+ Usage();
+}
+
+int ftwprocessfile(const char* fn, const struct stat *sb, int typeflag)
+{
+ processfile(fn, sb, typeflag);
return 0;
}
int main(int argc, char **argv)
{
+ const char *regexp_string;
thisprog = argv[0];
argc--; argv++;
-
+
while (argc > 0 && **argv == '-') {
(*argv)++;
if (!(**argv))
@@ -794,6 +858,10 @@
name = *(++argv); argc--;
goto b1;
case 'R': op_flags |= OPT_R; break;
+ case 'r': op_flags |= OPT_r; if (argc < 2) Usage();
+ regexp_string = *(++argv); argc--;
+ goto b1;
+ case 's': antiverbose++; break;
case 'S': op_flags |= OPT_S; break;
case 'T': op_flags |= OPT_T; break;
case 'v': op_flags |= OPT_v; if (argc < 2) Usage();
@@ -813,14 +881,28 @@
dotests();
exit(0);
}
-
+ if ((op_flags & OPT_r) && !(op_flags & OPT_n)) {
+ Usage();
+ }
+
if (op_flags & OPT_S) {
if (argc != 1)
Usage();
restore(argv[0]);
exit(0);
}
-
+ regex_t regexp;
+ if (op_flags & OPT_r) {
+ int err = regcomp(®exp, regexp_string, REG_NOSUB|REG_EXTENDED);
+ if (err) {
+ char errmsg[200];
+ regerror(err, ®exp, errmsg, 200);
+ cerr << "regcomp(" << regexp_string << ") error: " << errmsg <<
+ endl;
+ exit(1);
+ }
+ }
+
// Default option is 'list'
if ((op_flags&(OPT_l|OPT_n|OPT_x)) == 0)
op_flags |= OPT_l;
@@ -829,6 +911,7 @@
if (argc == 0)
readstdin = true;
+ int exitvalue = 0;
for (;;) {
const char *fn = 0;
if (argc > 0) {
@@ -844,19 +927,25 @@
break;
if (op_flags & OPT_R) {
- if (ftw(fn, processfile, 20))
+ if (ftw(fn, ftwprocessfile, 20))
exit(1);
- } else {
- processfile(fn, 0, 0);
+ } else if (op_flags & OPT_r) {
+ if (!regex_test(fn, ®exp)) {
+ exitvalue = 1;
+ }
+ } else {
+ if (!processfile(fn, 0, 0)) {
+ exitvalue = 1;
+ }
}
}
- exit(0);
+ exit(exitvalue);
}
static void fatal(const string& s)
{
- perror(s.c_str());
+ printsyserr(s.c_str());
exit(1);
}
@@ -957,115 +1046,113 @@
static const char *NAMES[] = {"ORG.PXATTR.NAME1", "ORG.PXATTR.N2",
"ORG.PXATTR.LONGGGGGGGGisSSSHHHHHHHHHNAME3"};
static const char *VALUES[] = {"VALUE1", "VALUE2", "VALUE3"};
- static bool verbose = true;
/* Create test file if it doesn't exist, remove all attributes */
int fd = open(tfn, O_RDWR|O_CREAT, 0755);
if (fd < 0) {
- perror("open/create");
+ printsyserr("open/create");
exit(1);
}
- if (verbose)
- fprintf(stdout, "Cleanup old attrs\n");
+ if (!antiverbose)
+ message("Cleanup old attrs\n");
vector<string> names;
if (!pxattr::list(tfn, &names)) {
- perror("pxattr::list");
+ printsyserr("pxattr::list");
exit(1);
}
for (vector<string>::const_iterator it = names.begin();
it != names.end(); it++) {
string value;
if (!pxattr::del(fd, *it)) {
- perror("pxattr::del");
+ printsyserr("pxattr::del");
exit(1);
}
}
/* Check that there are no attributes left */
names.clear();
if (!pxattr::list(tfn, &names)) {
- perror("pxattr::list");
+ printsyserr("pxattr::list");
exit(1);
}
if (names.size() != 0) {
- fprintf(stderr, "Attributes remain after initial cleanup !\n");
+ errno=0;printsyserr("Attributes remain after initial cleanup !\n");
for (vector<string>::const_iterator it = names.begin();
it != names.end(); it++) {
- fprintf(stderr, "%s\n", (*it).c_str());
+ if (antiverbose < 2)
+ cerr << *it << endl;
}
exit(1);
}
/* Create attributes, check existence and value */
- if (verbose)
- fprintf(stdout, "Creating extended attributes\n");
+ message("Creating extended attributes\n");
for (int i = 0; i < 3; i++) {
if (!pxattr::set(fd, NAMES[i], VALUES[i])) {
- perror("pxattr::set");
+ printsyserr("pxattr::set");
exit(1);
}
}
- if (verbose)
- fprintf(stdout, "Checking creation\n");
+ message("Checking creation\n");
for (int i = 0; i < 3; i++) {
string value;
if (!pxattr::get(tfn, NAMES[i], &value)) {
- perror("pxattr::get");
+ printsyserr("pxattr::get");
exit(1);
}
if (value.compare(VALUES[i])) {
- fprintf(stderr, "Wrong value after create !\n");
+ errno = 0;
+ printsyserr("Wrong value after create !");
exit(1);
}
}
/* Delete one, check list */
- if (verbose)
- fprintf(stdout, "Delete one\n");
+ message("Delete one\n");
if (!pxattr::del(tfn, NAMES[1])) {
- perror("pxattr::del one name");
+ printsyserr("pxattr::del one name");
exit(1);
}
- if (verbose)
- fprintf(stdout, "Check list\n");
+ message("Check list\n");
for (int i = 0; i < 3; i++) {
string value;
if (!pxattr::get(fd, NAMES[i], &value)) {
if (i == 1)
continue;
- perror("pxattr::get");
+ printsyserr("pxattr::get");
exit(1);
} else if (i == 1) {
- fprintf(stderr, "Name at index 1 still exists after deletion\n");
+ errno=0;
+ printsyserr("Name at index 1 still exists after deletion\n");
exit(1);
}
if (value.compare(VALUES[i])) {
- fprintf(stderr, "Wrong value after delete 1 !\n");
+ errno = 0;
+ printsyserr("Wrong value after delete 1 !");
exit(1);
}
}
/* Test the CREATE/REPLACE flags */
// Set existing with flag CREATE should fail
- if (verbose)
- fprintf(stdout, "Testing CREATE/REPLACE flags use\n");
+ message("Testing CREATE/REPLACE flags use\n");
if (pxattr::set(tfn, NAMES[0], VALUES[0], pxattr::PXATTR_CREATE)) {
- fprintf(stderr, "Create existing with flag CREATE succeeded !\n");
+ errno=0;printsyserr("Create existing with flag CREATE succeeded !\n");
exit(1);
}
// Set new with flag REPLACE should fail
if (pxattr::set(tfn, NAMES[1], VALUES[1], pxattr::PXATTR_REPLACE)) {
- fprintf(stderr, "Create new with flag REPLACE succeeded !\n");
+ errno=0;printsyserr("Create new with flag REPLACE succeeded !\n");
exit(1);
}
// Set new with flag CREATE should succeed
if (!pxattr::set(fd, NAMES[1], VALUES[1], pxattr::PXATTR_CREATE)) {
- fprintf(stderr, "Create new with flag CREATE failed !\n");
+ errno=0;printsyserr("Create new with flag CREATE failed !\n");
exit(1);
}
// Set existing with flag REPLACE should succeed
if (!pxattr::set(fd, NAMES[0], VALUES[0], pxattr::PXATTR_REPLACE)) {
- fprintf(stderr, "Create existing with flag REPLACE failed !\n");
+ errno=0;printsyserr("Create existing with flag REPLACE failed !\n");
exit(1);
}
close(fd);