Age | Commit message (Collapse) | Author |
|
bash's extremely fancy internal awareness of how the environment looks
means that, if you directly call the underlying libc "unsetenv" on
a variable, bash can end up trying to access a null pointer. Fixing
this generically is actually rather hard; you can't really avoid
writing to environ on fork() or popen(), even if you change all
execv*() functions to use the execv*e() variants. So for now, instead
of unsetting the variable, set it to an empty string.
Thanks to Saur in IRC for spotting this and helping debug it.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
Based on a submission from Anton Gerasimov <anton@advancedtelematic.com>
On some systems, with some kernel configs, "cp -a" apparently tries to
set an empty ACL list, with a valid header but no contents, which causes
strange and mysterious behavior later if we actually create such an entry.
So filter that out, also sanity-check a couple of other things.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
Currently, the Makefile rebuilds the binary at every invokation of
the command make:
$ make
cc -pipe -std=gnu99 -Wall -W -Wextra -fPIC
-D_LARGEFILE64_SOURCE -D_ATFILE_SOURCE -m64
-DPSEUDO_PREFIX='"/opt"' -DPSEUDO_SUFFIX='""'
-DPSEUDO_BINDIR='"bin"' -DPSEUDO_LIBDIR='"lib64"'
-DPSEUDO_LOCALSTATEDIR='"var/pseudo"' -DPSEUDO_VERSION='"1.8.1"'
-DUSE_MEMORY_DB -DPSEUDO_PASSWD_FALLBACK='""'
-DPSEUDO_XATTR_SUPPORT -O2 -g -o bin/pseudo \ pseudo.o
pseudo_server.o pseudo_client.o pseudo_ipc.o \ pseudo_db.o
pseudo_tables.o pseudo_util.o -lsqlite3 -lpthread -ldl
-lpthread cc -pipe -std=gnu99 -Wall -W -Wextra -fPIC
-D_LARGEFILE64_SOURCE -D_ATFILE_SOURCE -m64
-DPSEUDO_PREFIX='"/opt"' -DPSEUDO_SUFFIX='""'
-DPSEUDO_BINDIR='"bin"' -DPSEUDO_LIBDIR='"lib64"'
-DPSEUDO_LOCALSTATEDIR='"var/pseudo"' -DPSEUDO_VERSION='"1.8.1"'
-DUSE_MEMORY_DB -DPSEUDO_PASSWD_FALLBACK='""'
-DPSEUDO_XATTR_SUPPORT -O2 -g -o bin/pseudodb pseudodb.o \
pseudo_db.o pseudo_tables.o pseudo_util.o pseudo_ipc.o -lsqlite3
-lpthread -ldl -lpthread
The fault comes from the $(BIN) directory prerequesite.
According to the documention of GNU make(*), directory prerequesites
normally go to <order-only-prerequisites>:
targets: normal-prerequisites | order-only-prerequisites
> Consider an example where your targets are to be placed in a separate
> directory, and that directory might not exist before make is run. In
> this situation, you want the directory to be created before any
> targets are placed into it but, because the timestamps on directories
> change whenever a file is added, removed, or renamed, we certainly
> don’t want to rebuild all the targets whenever the directory’s
> timestamp changes. One way to manage this is with order-only
> prerequisites: make the directory an order-only prerequisite on all
> the targets.
>
> OBJDIR := objdir
> OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
>
> $(OBJDIR)/%.o : %.c
> $(COMPILE.c) $(OUTPUT_OPTION) $<
>
> all: $(OBJS)
>
> $(OBJS): | $(OBJDIR)
>
> $(OBJDIR):
> mkdir $(OBJDIR)
>
> Now the rule to create the objdir directory will be run, if needed,
> before any ‘.o’ is built, but no ‘.o’ will be built because the
> objdir directory timestamp changed.
This patch fixes this behavior. No binaries are rebuilt when the command
make is re-run:
$ make
make: Nothing to be done for 'all'.
*: https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html
Signed-off-by: Gaël PORTAY <gael.portay@savoirfairelinux.com>
Signed-off-by: Seebs <seebs@seebs.net>
|
|
|
|
When deleting a specific file, delete xattrs only if it's the last file
with that device/inode pair.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
Each manual page should start with a "NAME" section, which lists the
name and a brief description of the page separated by "\-".
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
Signed-off-by: Seebs <seebs@seebs.net>
|
|
file. Before setting a file's capabilities with cap_set_file() (which uses
setxattr()) it calls cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag,
CAP_SET). cap_set_flag() uses the capset syscall to raise the process'
effective capability. In most cases if the process isn't running as root
this will fail and setcap will exit with an error. Because setxattr is
intercepted by pseudo it's unnecessary for setcap to call capset().
Override capset with a pseudo function that does nothing and always
returns 0.
Signed-off-by: George McCollister <george.mccollister at gmail.com>
Signed-off-by: Seebs <seebs@seebs.net>
|
|
When tclsh forks it can create new threads in the child process, in a
pthread_atfork() handler. Running this under pseudo results in a
deadlock since the pseudo_lock() call in the new thread in the child
process premanently believes that the mutex is already locked by another
thread (which actually only existed in the parent process).
The provided test cases reproduces this. Similar hangs can also been
seen in other cases, such as when attempting to use vim's cscope support
under pseudo.
Fix it by reseting the mutex in a pthread_atfork() child function.
Signed-off-by: Rabin Vincent <rabinv@axis.com>
Signed-off-by: Seebs <seebs@seebs.net>
|
|
test-umask fails if run twice. Make it remove the created temporary
files before the test.
Signed-off-by: Rabin Vincent <rabinv@axis.com>
Signed-off-by: Seebs <seebs@seebs.net>
|
|
Helped-by: Damien Riegel <damien.riegel@savoirfairelinux.com>
Helped-by: Alexandre Leblanc <alexandre.leblanc@savoirfairelinux.com>
Signed-off-by: Gaël PORTAY <gael.portay@savoirfairelinux.com>
Signed-off-by: Seebs <seebs@seebs.net>
|
|
File "./makewrappers", line 459
print port
^
SyntaxError: Missing parentheses in call to 'print'
Signed-off-by: Gaël PORTAY <gael.portay@savoirfairelinux.com>
Signed-off-by: Seebs <seebs@seebs.net>
---
maketables | 12 ++++++------
makewrappers | 32 ++++++++++++++++----------------
templatefile.py | 8 ++++----
3 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/maketables b/maketables
index b32312e..0726485 100755
--- a/maketables
+++ b/maketables
@@ -73,7 +73,7 @@ class DataType:
for col in columns:
indexed = False
if col.startswith("FLAGS"):
- print "Flags: set for %s" % self.name
+ print("Flags: set for %s" % self.name)
self.flags = True
continue
if col.startswith("INDEXED "):
@@ -248,7 +248,7 @@ def main():
template_file.emit('header')
templates.append(template_file)
except IOError:
- print "Invalid or malformed template %s. Aborting." % path
+ print("Invalid or malformed template %s. Aborting." % path)
exit(1)
for filename in sys.argv[1:]:
@@ -256,15 +256,15 @@ def main():
sys.stdout.write("%s: " % filename)
datatype = DataType(filename)
datatypes.append(datatype)
- print datatype.__repr__()
- print ""
+ print(datatype.__repr__())
+ print("")
- print "Writing datatypes...",
+ print("Writing datatypes...")
for datatype in datatypes:
# populate various tables and files with each datatype
for template_file in templates:
template_file.emit('body', datatype)
- print "done. Cleaning up."
+ print("done. Cleaning up.")
for template_file in templates:
# clean up files
diff --git a/makewrappers b/makewrappers
index 303e2cc..bac856b 100755
--- a/makewrappers
+++ b/makewrappers
@@ -456,7 +456,7 @@ additional ports to include.
self.name = port
self.subports = []
self.preports = []
- print port
+ print(port)
if os.path.exists(self.portfile("pseudo_wrappers.c")):
self.wrappers = self.portfile("pseudo_wrappers.c")
@@ -504,17 +504,17 @@ additional ports to include.
prefuncs = pre.functions()
for name in prefuncs.keys():
if name in mergedfuncs:
- print "Warning: %s from %s overriding %s" % (name, pre.name, mergedfuncs[name].port)
+ print("Warning: %s from %s overriding %s" % (name, pre.name, mergedfuncs[name].port))
mergedfuncs[name] = prefuncs[name]
for name in self.funcs.keys():
if name in mergedfuncs:
- print "Warning: %s from %s overriding %s" % (name, self.name, mergedfuncs[name].port)
+ print("Warning: %s from %s overriding %s" % (name, self.name, mergedfuncs[name].port))
mergedfuncs[name] = self.funcs[name]
for sub in self.subports:
subfuncs = sub.functions()
for name in subfuncs.keys():
if name in mergedfuncs:
- print "Warning: %s from %s overriding %s" % (name, sub.name, mergedfuncs[name].port)
+ print("Warning: %s from %s overriding %s" % (name, sub.name, mergedfuncs[name].port))
mergedfuncs[name] = subfuncs[name]
return mergedfuncs
@@ -576,11 +576,11 @@ def process_wrapfuncs(port):
func.directory = directory
funcs[func.name] = func
sys.stdout.write(".")
- except Exception, e:
- print "Parsing failed:", e
+ except Exception(e):
+ print("Parsing failed:", e)
exit(1)
funclist.close()
- print ""
+ print("")
return funcs
def main(argv):
@@ -599,35 +599,35 @@ def main(argv):
for path in glob.glob('templates/*'):
try:
- print "Considering template: " + path
+ print("Considering template: " + path)
source = TemplateFile(path)
if source.name.endswith('.c') or source.name.endswith('.h'):
source.emit('copyright')
source.emit('header')
sources.append(source)
except IOError:
- print "Invalid or malformed template %s. Aborting." % path
+ print("Invalid or malformed template %s. Aborting." % path)
exit(1)
try:
port = Port('common', sources)
except KeyError:
- print "Unknown uname -s result: '%s'." % uname_s
- print "Known system types are:"
- print "%-20s %-10s %s" % ("uname -s", "port name", "description")
+ print("Unknown uname -s result: '%s'." % uname_s)
+ print("Known system types are:")
+ print("%-20s %-10s %s" % ("uname -s", "port name", "description"))
for key in host_ports:
- print "%-20s %-10s %s" % (key, host_ports[key],
- host_descrs[host_ports[key]])
+ print("%-20s %-10s %s" % (key, host_ports[key],
+ host_descrs[host_ports[key]]))
# the per-function stuff
- print "Writing functions...",
+ print("Writing functions...")
all_funcs = port.functions()
for name in sorted(all_funcs.keys()):
# populate various tables and files with each function
for source in sources:
source.emit('body', all_funcs[name])
- print "done. Cleaning up."
+ print("done. Cleaning up.")
for source in sources:
# clean up files
diff --git a/templatefile.py b/templatefile.py
index 2789b22..abf9a2c 100644
--- a/templatefile.py
+++ b/templatefile.py
@@ -79,13 +79,13 @@ class TemplateFile:
return
path = Template(self.path).safe_substitute(item)
if os.path.exists(path):
- # print "We don't overwrite existing files."
+ # print("We don't overwrite existing files.")
return
self.file = open(path, 'w')
if not self.file:
- print "Couldn't open '%s' (expanded from %s), " \
+ print("Couldn't open '%s' (expanded from %s), " \
"not emitting '%s'." % \
- (path, self.path, template)
+ (path, self.path, template))
return
def emit(self, template, item=None):
@@ -103,7 +103,7 @@ class TemplateFile:
self.file.write(templ.safe_substitute(item))
self.file.write("\n")
else:
- print "Warning: Unknown template '%s'." % template
+ print("Warning: Unknown template '%s'." % template)
if self.file_per_item:
if self.file:
--
2.10.1
|
|
File "./makewrappers", line 327
return """/* This function is not called if pseudo is configured --enable-force-async */
^
TabError: inconsistent use of tabs and spaces in indentation
Signed-off-by: Gaël PORTAY <gael.portay@savoirfairelinux.com>
Signed-off-by: seebs <seebs@seebs.net>
---
makewrappers | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/makewrappers b/makewrappers
index e9191ed..303e2cc 100755
--- a/makewrappers
+++ b/makewrappers
@@ -324,7 +324,7 @@ class Function:
def maybe_async_skip(self):
if self.async_skip:
- return """/* This function is not called if pseudo is configured --enable-force-async */
+ return """/* This function is not called if pseudo is configured --enable-force-async */
#ifdef PSEUDO_FORCE_ASYNC
if (!pseudo_allow_fsync) {
PROFILE_DONE;
@@ -333,7 +333,7 @@ class Function:
#endif
""" % self.async_skip
else:
- return ""
+ return ""
def comment(self):
"""declare self (in a comment)"""
@@ -393,11 +393,11 @@ class Function:
def rc_format(self):
"""the format string to use for the return value"""
- return typedata.get(self.type, { 'format': '[%s]', 'value': '"' + self.type + '"' })['format']
+ return typedata.get(self.type, { 'format': '[%s]', 'value': '"' + self.type + '"' })['format']
def rc_value(self):
"""the value to pass for the format string for the return value"""
- return typedata.get(self.type, { 'format': '[%s]', 'value': '"' + self.type + '"' })['value']
+ return typedata.get(self.type, { 'format': '[%s]', 'value': '"' + self.type + '"' })['value']
def rc_decl(self):
"""declare rc (if needed)"""
@@ -456,7 +456,7 @@ additional ports to include.
self.name = port
self.subports = []
self.preports = []
- print port
+ print port
if os.path.exists(self.portfile("pseudo_wrappers.c")):
self.wrappers = self.portfile("pseudo_wrappers.c")
@@ -522,11 +522,11 @@ additional ports to include.
return '#define PSEUDO_PORT_%s 1' % string.upper(self.name).replace('/', '_')
def portdeps(self):
- deps = []
- if self.wrappers:
- deps.append(self.wrappers)
- if self.portdef_file:
- deps.append(self.portdef_file)
+ deps = []
+ if self.wrappers:
+ deps.append(self.wrappers)
+ if self.portdef_file:
+ deps.append(self.portdef_file)
if deps:
return 'pseudo_wrappers.o: %s' % ' '.join(deps)
else:
@@ -590,7 +590,7 @@ def main(argv):
for arg in argv:
name, value = arg.split('=')
- os.environ["port_" + name] = value
+ os.environ["port_" + name] = value
# error checking helpfully provided by the exception handler
copyright_file = open('guts/COPYRIGHT')
@@ -599,9 +599,9 @@ def main(argv):
for path in glob.glob('templates/*'):
try:
- print "Considering template: " + path
+ print "Considering template: " + path
source = TemplateFile(path)
- if source.name.endswith('.c') or source.name.endswith('.h'):
+ if source.name.endswith('.c') or source.name.endswith('.h'):
source.emit('copyright')
source.emit('header')
sources.append(source)
--
2.10.1
|
|
If you're running pseudo in docker, a script that creates a pseudo
daemon can exit, causing docker to kill pseudo before it's done writing
the database.
Since the client sending the shutdown request doesn't have its socket
closed explicitly by the server, we can just read from the socket in
the client to create a delay until the actual exit, which can take
a while if there's an in-memory DB.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
The output from configure with no --prefix is not as explicit as
it should perhaps be about why it's failing and printing a usage
message.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
Fix provided by Patrick Ohly <patrick.ohly@intel.com>. This resolves
the actual cause of the path length mismatches, and explains why
I couldn't quite explain why the previous one had only sometimes
worked, also why it showed up on directories but not plain files.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
This reverts commit d5a6b5e2d23288452b374a1ffe32b6b3e52c13fc.
(Because it turns out I was wrong.)
|
|
For some reason, extended attributes were getting garbage
appended in some cases. Attempt to fix this.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
|
|
x32 compilation fails because x32 defines __amd64__ and thus pseudo tries
to grab a version of memcpy that's useful for amd64, and this isn't
available. Try disabling that, see what happens.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
The sed command for arch_cflags wouldn't work if arch_cflags contained
commas. Changing punctuation just moves the problem elsewhere. Instead,
use backslashes to escape them.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
There was a bug in rename(), which was duplicated when renameat() was
implemented, and which got fixed two years ago for rename(), but no
one ever uses renameat() so it didn't get fixed there. Thanks
to Anton Gerasimov <anton@advancedtelematic.com> for the bug report
and patch.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
So it turns out that pseudo_logfile() was returning 0 or -1, and
pseudo_debug_logfile() was expecting it to be the correct file descriptor
to use. And it's basically a mystery that any of that ever worked.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
When the client spawns a pseudo server, it starts out sending diagnostics
to stderr. This can be spammy in some cases with races during startup;
everything resolves, but we get scary-looking diagnostics. So shove
those into a log file.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
If the parent exits due to child process being slow, getppid() will return
1, and we'll send SIGUSR1 to init, which can break things like dumbinit
which aren't adequately protected against non-root processes sending them
signals.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
Caught by joshuagl: In pdb_clear_unused_xattrs(), the prepared statement
has no bound parameters, so there's no bindings to clear.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
When deleting files, we *do* know the inode and attribute, most of the
time, so we pass those in whenever possible. The full purge of unmatched
xattrs should not happen when the correct dev/ino are believed to be known.
Signed-off-by: Seebs <seebs@seebs.net>
|
|
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
|
|
Don't call sqlite3_finalize() on the static sqlite3_stmt scan as
we reuse it later. The sqlite3_reset() and sqlite4_clear_bindings()
calls are sufficient to reset the prepared statement and reusing
the sqlite3_stmt that has had sqlite3_finalize() on it results in
segfaults and data loss.
Signed-off-by: Joshua Lock <joshua.g.lock@intel.com>
|
|
Signed-off-by: Joshua Lock <joshua.g.lock@intel.com>
|
|
Signed-off-by: Joshua Lock <joshua.g.lock@intel.com>
|
|
So a recent change to ld.so behavior revealed that pseudo was not
always correctly detecting that a function hadn't been found by the
RTLD_NEXT search. This only happened for functions which genuinely
didn't exist and wouldn't get called (like mknod on Linux, which
is actually always done as an inline function that calls __xmknod),
but when the diagnostics started showing up, it broke things. Fix it
so the diagnostics would have shown up when things were originally
broken, also fix the resulting diagnostics.
Signed-off-by: Peter Seebach <peter.seebach@windriver.com>
|
|
|
|
These changes are enough to justify a .1 upgrade.
|
|
Respect environment-set $(LDFLAGS).
Fix provided by kergoth, I'm just merging it.
|
|
Handle various ways that a dev/ino pair can cease to have files and thus
need to cease to have xattrs. Also handle weird stuff like moving a file
across filesystems when it was one of multiple links to an inode with
extended attributes.
|
|
extended attributes are a property of inodes, not paths. There can be
multiple file database entries for a single inode, so switch to using
inodes rather than paths.
Still to-do: Delete them when deleting the last file with a given device
and inode.
|
|
The variable name is required but wasn't being extracted from the client's
message, resulting in xattr removal never working. This does not fully
address some deeper problems with the xattr implementation, but at least
the common removal case works.
|
|
The pseudo server should probably always run with 022 umask so the
sockets, database files, and such get created with sane modes.
|
|
Since the pseudo socket is actually created by a call to bind, the
bind call could create a file, which means it needs to record a
database entry.
|
|
So we had this really strange problem where, sometimes but not always,
pseudo would have strange problems on startup, where the pseudo server
would end up running under pseudo. And this produced the most fascinating
thing, which was:
unsetenv("LD_PRELOAD");
assert(getenv("LD_PRELOAD") == NULL);
for (int i = 0; environ[i]; ++i) {
assert(strncmp(environ[i], "LD_PRELOAD=", 11));
}
(pseudocode untested)
This would crash on the environ search. Because getenv() was not searching
environ.
WHAT.
So it turns out, *bash overrides getenv, setenv, and so on*. Under those
names. Hiding the glibc ones. And this creates horrible problems if you
assumed that your code could call those functions and expect them to work.
So as a workaround, pseudo now uses dlsym to find getenv, etc., from
glibc, and invokes those directly if possible. Also the client now uses
unwrapped fork/exec for spawning the server, which cleans up the
behavior of that code quite a bit.
|
|
Improved/simplified logic for the client spawning servers, to make it
(I hope) easier to see what it's trying to do and when. Also clearer
diagnostics about what may have gone wrong, and I don't check the pid file
unless there's a problem.
|
|
Server process now waits for its forked child when daemonizing, allowing
us to yield meaningful exit status. Lock is now taken by the child, since
it has a way to tell the parent about the exit status. (We send SIGUSR1 to
the server to cause the wait loop to stop when the client is ready to go.)
This allows us to switch to fcntl locking, which should in theory allow us
to run with the pseudo directory NFS-mounted. Woot!
Also mark a couple of overly spammy messages as PDBGF_VERBOSE to reduce the
volume of uninteresting dup spam when looking at client behaviors.
Client now uses execve to spawn server to work around a very strange behavior
of unsetenv.
Signed-off-by: Peter Seebach <peter.seebach@windriver.com>
|
|
This is the big overhaul to have the server provide meaningful exit status
to clients.
In the process, I discovered that the server was running with signals blocked
if launched by a client, which is not a good thing, and prevented this from
working as intended.
Still looking to see why more than one server spawn seems to happen.
|
|
Improve event logging a little bit more, increase default event log size,
reduce retries (we shouldn't need that many if nothing's wrong), and make
the server log timestamps during database cleanup, since I'm suspicious of
that as a possible source of delays. Also cause server to emit a useful exit
status if it can't get a lock, and client to check server exit status when
spawning server.
|
|
For debugging the client/server startup, add an event logger to allow
better recording of events that we may, or may not, want to dump out
listings of later.
|
|
For sound reasons, the server wants to be sure no client is on fd 2. However,
the client shouldn't force the pseudo log file to be fd 2; it should leave
stderr alone when a log file is specified.
|
|
Recent fixes mostly to do with race conditions on server respawn, also
some xattr tweaks.
|
|
First, if aborting, display message even when no debugging is set, because
that's probably a big deal.
Second, if you use "pseudo <cmd>", try to die with the same signal that killed
the child process, if it died from a signal rather than exiting cleanly. (You
can't just pass the exit status out in that case, because exit(N) doesn't work
for N outside the range of non-signal exit statuses.)
|
|
There's a possible race condition if multiple clients try to start while
the server's down, especially if it's shutting down and thus holding a lock
but ignoring them. Logic altered to retry more often, at greater intervals.
Also, we are fine with being unable to spawn the server, because that can
happen if another client spawned it successfully. So we just retry sending
the message in a bit if we couldn't spawn a server, or immediately if we
could. (Because "could" spawn a server includes successfully communicating
with the newly-spawned server; the server-side code makes sure that the
child process won't exit before we expect such attempts to work, even if
they take a while.)
|
|
Only cancel shutdown if a client showed up. Change timeout from 1 second to
3 seconds, so it gets at least one time through the loop.
|