daemon process mount failed - linux

I am programming a Linux distribution C program. When daemon process read a MSG from the client, it will fork a child process, then mount a "NFS" dir to local host and do the compute task on this NFS dir.
However this is NFS is IBM ClearCase dynamic view which is called "MVFS" rather than "NFS".
So I have to exec "cleartool setview xxyyzz" to mount this view.
But I tried several methods such as fork() + execvp, system(shell), but never succeed.
Below is the code and shell:
void my_system();
int main(int argc, char** argv)
{
pid_t pid=fork();
if(pid!=0) exit(0);
if(setsid()==-1)
{
printf("setsid failed.");
exit(-1);
}
umask(0);
chdir("/tmp");
int i;
for(i=0;i<3;i++)
close(i);
FILE* logfd=fopen("/tmp/ccdcc.log","a+");
dup2(fileno(logfd),STDOUT_FILENO);
dup2(fileno(logfd),STDERR_FILENO);
fclose(logfd);
my_system(); //method1
system("/tmp/ccdccshell"); //method2
sleep(SEVERALTIME);
}
void my_system()
{
pid_t pid=fork();
if(pid!=0) return;
char *arg1[]={"cleartool","setview","zzzzzz"};
char *arg2[]={"cd","/proj/layer/mak"};
char *arg3[]={"mycmd"};
execvp("cleartool",arg1);
execvp("cd",arg2);
execvp("mycmd",NULL);
}
xxx#yyy> cat /tmp/ccdccshell
#!/bin/sh
#this command will mount a dynamic view and source some profile.
cleartool setview zzzzzz
#this path is under the mounted path
cd /proj/layer/mak
#to test where we are
pwd
#call my prog.
mycmd
I failed "cleartool...." everytime. There's no view been mounted.
"pwd" always return the path "/".
Could you tell me how to finish my program?

Don't use cleartool setview: it spawns a subshell which would not be visible from your sameon.
Simply use the full dynamic view path:
/view/myDynView
# under which you would see:
/view/myDynView/vobs/MyVob
All you need is for the view to be started.

Related

Can someone trace the reason for segmentation fault?

public class Watcher: Object
{
private int _fd;
private uint _watch;
private IOChannel _channel;
private uint8[] _buffer;
private int BUFFER_LENGTH;
public Watcher(string path, Linux.InotifyMaskFlags mask){
_buffer = new uint8[BUFFER_LENGTH];
//➔ Initialize notify subsystem
_fd = Linux.inotify_init();
if(_fd < 0){
error(#"Failed to initialize the notify subsystem: $(strerror(errno))");
}
//➔ actually adding abstraction to linux file descriptor
_channel = new IOChannel.unix_new(_fd);
//➔ watch the channel for given condition
//➔ IOCondition.IN => When the channel is ready for reading , IOCondition.HUP=>Hangup(Error)
_watch = _channel.add_watch(IOCondition.IN | IOCondition.HUP, onNotified);
if(_watch < 0){
error(#"Failed to add watch to channel");
}
//➔ Tell linux kernel to watch for any mask(for ex; access, modify) on a given filepath
var ok = Linux.inotify_add_watch(_fd, path, mask);
if(ok < 0){
error(#"Failed to add watch to path -- $path : $(strerror(errno))");
}
print(#"Watching for $(mask) on $path");
}
protected bool onNotified(IOChannel src, IOCondition condition)
{
if( (condition & IOCondition.HUP) == IOCondition.HUP){
error(#"Received hang up from inotify, can't get update");
}
if( (condition & IOCondition.IN) == IOCondition.IN){
var bytesRead = Posix.read(_fd, _buffer, BUFFER_LENGTH);
Linux.InotifyEvent *pevent = (Linux.InotifyEvent*) _buffer;
handleEvent(*pevent);
}
return true;
}
protected void handleEvent(Linux.InotifyEvent ev){
print("Access Detected!\n");
Posix.exit(0);
}
~Watcher(){
if(_watch != 0){
Source.remove(_watch);
}
if(_fd != -1){
Posix.close(_fd);
}
}
}
int main(string[] args) requires (args.length > 1)
{
var watcher = new Watcher(args[1], Linux.InotifyMaskFlags.ACCESS);
var loop = new MainLoop();
loop.run();
return 0;
}
The above code can be found on "Introducing Vala Programming - Michael Lauer"
Proof of failure:
Image displaying failure on access to the file being watched for access
Terminal 1:
./inotifyWatcher
Terminal 2:
cat
As soon as I access the file, segmentation fault occurs.
I have also tried using gdb for the cause of failure, but it's mostly cryptic for me. I am using parrot(debian/64-bit) on my machine. Also, I am new to this(stackoverflow, linux kernel program).
Vala source line numbers can be included in the binary when compiling with the --debug switch. The line numbers appear in the .debug_line DWARF section of an ELF binary:
valac --debug --pkg linux inotifyWatcher.vala
Run the binary using gdb in the first terminal:
gdb --args ./inotifyWatcher .
(gdb) run
The dot specifies to watch the current directory. Then when the current directory is access with a command like ls the watching program segmentation faults. The output from GDB is:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401a86 in watcher_onNotified (self=0x412830, src=0x40e6e0, condition=G_IO_IN) at inotifyWatcher.vala:51
51 handleEvent(*pevent);
GDB includes the line number, 51, from the source file and shows the line.
So the problem is to do with reading from the file descriptor then passing the buffer to handleEvent. You probably want to check bytesRead is greater than zero and I'm not sure about the use of pointers in this example. Explicit pointers like that should rarely need to be used in Vala, it may require a change to the binding, e.g. using ref to modify the way the argument is passed.

How do I detect that a process failed to start, using apr_procattr_create from the Apache Portable Runtime on Ubuntu Linux?

I'm using the Apache Portable Runtime to start a process via apr_procattr_create. My failing test case is when the called command does not exist on the system. On Windows, apr_proc_create returns a non-success error code if the executable does not exist. On Linux, I cannot work out how to detect the failure. According to the documentation, apr_procattr_error_check_set might be expected to do the trick, but it does not appear to.
Q: How can I detect that a process failed to start on linux with APR apr_proc_create?
Here's my code:
/**
* Run a command asynchronously
* The command name is the first element of args. The remaining elements are
* the arguments for the command
*/
apr_status_t mynamespace::RunCommandUnchecked(const std::vector<std::string> & args)
{
std::vector<const char*> cArgs;
for (size_t i = 0; i < args.size(); ++i)
cArgs.push_back(args[i].c_str());
cArgs.push_back(nullptr);
apr_procattr_t *procAttr;
apr_procattr_create(&procAttr, this->impl->pool.get_Pool());
// send the process's std out to a temporary file
apr_procattr_child_out_set(procAttr, this->impl->outputFile, nullptr);
// block the process from accessing stdin & stderr on the current process
apr_procattr_child_in_set(procAttr, nullptr, nullptr);
apr_procattr_child_err_set(procAttr, nullptr, nullptr);
// prefer to report errors to the caller.
apr_procattr_error_check_set(procAttr, 1);
// Ensure the path is searched for the command to run
apr_procattr_cmdtype_set(procAttr, APR_PROGRAM_PATH);
return apr_proc_create(&this->impl->proc, cArgs[0], cArgs.data(), nullptr, procAttr, this->impl->pool.get_Pool());
}
My (failing on linux) test case is as follows:
/*
*
* In this test, we execute a command that does not exist. We expect
* a non-success failure code.
**/
void CommandRunnerTests::CommandDoesNotExistUnchecked()
{
mynamespace::CommandRunner runner(app::get_ApplicationLog());
auto rv = runner.RunCommandUnchecked({ "pants-trousers-stockings.exe" });
// We expect a non-success error code to be returned.
// This assert fails on linux.
CPPUNIT_ASSERT(rv != APR_SUCCESS);
#ifdef _WIN32
std::string expected("The system cannot find the file specified.");
#else
std::string expected("command not found");
#endif
auto msg = app::GetAprErrorMessage(rv);
CPPUNIT_ASSERT_STRING_EQUAL(expected, boost::trim_copy(msg));
}
When I execute the same command on the (bash) shell, the output is as follows
me#pc:~/code$ pants-trousers-stockings.exe
pants-trousers-stockings.exe: command not found
me#pc:~/code$ echo $?
127
I'm currently using APR version 1.4.6. I can update to a newer version if there are any relevant changes, but I don't see any in the release notes.
The code works as expected on Windows.
My Linux OS is uBuntu 14.04
Calling apr_proc_wait doesn't work to detect the failure, it just tells me APR_PROC_EXIT (process terminated normally) and APR_CHILD_DONE (child is no longer running).

Why I couldn't use mount --bind /proc/<pid>/ns/mnt to another file in ubuntu?

Recently, I am learning about linux namespaces.
I hope even if the process ends, I could still attach the namespace that process is in.
Someone told I could use mount --bind /proc/<pid>/ns/pid ./pid to keep this file open. So I tried it.
When I mount uts, user, ipc, pid, net... They are all okay..
root#ubuntu:/home/jiashenh/workspace# touch uts
root#ubuntu:/home/jiashenh/workspace# mount --bind /proc/171/ns/uts ./uts
But when it comes to mnt.... I used it in the same way ...
root#ubuntu:/home/jiashenh/workspace# touch mnt
root#ubuntu:/home/jiashenh/workspace# mount --bind /proc/171/ns/mnt ./mnt
mount: wrong fs type, bad option, bad superblock on /proc/171/ns/mnt,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail or so
It failed.....So could anyone told me how to fix it?
.
Bind mount for /proc/<pid>/ns/mnt really doesn't work if called within the same mount namespace.
However, bind mount for ns/mnt works if:
mount() is called from a process with another mount namespace, and
mount() is called from a process where the ns/mnt being mounted is visible.
Both requirements are met if mount() is called from a process forked before unshare() call that created ns/mnt entry being mounted.
(Note that after unshare() call, previously visible ns/mnt entries are no more visible and become broken symlinks).
Here is a test:
#define _GNU_SOURCE
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/mount.h>
int main(int argc, char** argv) {
int fd = open("/tmp/mnt.ns", O_CREAT | O_RDWR);
close(fd);
if (argc > 1) {
if (fork() == 0) {
sleep(1);
} else {
unshare(CLONE_NEWNS);
wait(NULL);
return 0;
}
}
char src[PATH_MAX] = {};
snprintf(src, sizeof(src), "/proc/%u/ns/mnt", (unsigned)getppid());
if (mount(src, "/tmp/mnt.ns", NULL, MS_BIND, NULL) != 0) {
printf("mount failed: %s\n", strerror(errno));
return 1;
}
else {
printf("mount ok\n");
}
return 0;
}
This test fails without fork() and unshare():
$ sudo ./a.out
mount failed: Invalid argument
But works if it calls fork() and unshare() before mount() (note the x arg):
$ sudo ./a.out x
mount ok
See this commit for unshare tool and also this patch.
Unfortunately, this behaviour specific to ns/mnt is not documented in namespaces(7).

How to tell if a file is on tmpfs given its path on Linux?

This might be a dumb question, but suppose I'm given a file path and I'd like to know if it points to a file on tmpfs (that is, it's an in-memory file). How can I do that using only Linux system calls? (That is, I can't go to the shell.)
Use the statfs syscall and see if the returned f_type field is TMPFS_MAGIC.
Here's a small utility demonstrating this:
#include <sys/vfs.h>
#include <linux/magic.h>
#include <stdio.h>
int main(int argc, char** argv) {
struct statfs info;
statfs(argv[1], &info);
if (info.f_type == TMPFS_MAGIC) {
printf("It's tmpfs\n");
return 0;
} else {
printf("It's not tmpfs\n");
return 1;
}
}
Example:
$ ./isittmpfs /etc/passwd
It's not tmpfs
$ ./isittmpfs /dev/shm/pulse-shm-1358569836
It's tmpfs
(NB: This is just an example of how to determine if a file is on tmpfs through syscalls. This answer does not suggest dropping to a shell even though the example code is invoked from a shell)

procps cause stack smashing

I've been writing a program trying to find itself using the procps library.
But for some reason it smashes the stack.
This is my code:
int main(){
PROCTAB *ptp;
proc_t task;
pid_t mypid[1];
mypid[0] = getpid();
printf("My id: %d\n", mypid[0]);
ptp = openproc(PROC_PID, mypid, 1);
if(readproc(ptp, &task)){
printf("Task id:%d\n",task.XXXID);
}
else{
printf("Error: could not find currect task\n");
}
closeproc(ptp);
printf("Done\n");
return 0;
}
The output i get when i run the program is:
$ ./test
My id is: 8514
Task id is:8514
Done
*** stack smashing detected ***: ./test terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb7688dd5]
/lib/i386-linux-gnu/libc.so.6(+0xffd8a)[0xb7688d8a]
./test[0x804863e]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75a24d3]
./test[0x80484f1]
======= Memory map: ========
...
Aborted (core dumped)
Any one has an idea why it happens?
Am I doing something wrong?
Thanks.
Edit:
I've looked at the header file and notice that I've made a wrong use of the openproc function the correct way to use it is (for pid) is to have the mypid array be null terminated, so I've change my code to:
int main(){
PROCTAB *ptp;
proc_t task;
pid_t mypid[2];
mypid[0] = getpid();
memset(&mypid[1], 0, sizeof(pid_t));
printf("My id: %d\n", mypid[0]);
ptp = openproc(PROC_PID, mypid);
if(readproc(ptp, &task)){
printf("Task id:%d\n",task.XXXID);
}
else{
printf("Error: could not find currect task\n");
}
closeproc(ptp);
printf("Done\n");
return 0;
}
and it still crushes the stack.
It works for me here. After getting that version of procps, it compiled and run fine:
$ gcc -Wall -Werror -o rp -L. -lproc-3.2.8 rp.c
$ ./rp
My id: 11468
Task id:11468
Done
Update
Try a modified version:
proc_t *result;
...
if((result = readproc(ptp, NULL))){
printf("Task id:%d\n",result->XXXID);
free(result);
}
A possible cause for your crash is the fact that the proc_t struct returned by readproc() has additional dynamically allocated elements, such as environment variables or command line arguments. A safer way is to let readproc() allocate the whole structure, and free it later using freeproc():
while ((proc_info = readproc(proc, nullptr)) != NULL) {
// do something with proc_info
freeproc(proc_info);
}

Resources