can you make make a function to handle permission denied on zsh like command not found - zsh

so I am using zsh. I have a bunch of functions that move me around the place - like if I type "bin" anywhere - I go to ~/bin etc. I do this by hooking into the command_not_found_handler as so:
command_not_found_handler() {
if [ -f ~/bin/marked/$1 ]; then
directory=$(<~/bin/marked/$1)"
echo cd \"$directory\" >~/source_function
return 0
...
and this works fantastically - anywhere I am, I can just type marker blah - it creates a marker, and from then on anywhere I am, if I type blah it will just go back to that directory I marked.
Except.
I have "." in my path. (Yes I know you think I shouldn't do that)
and if there happens to be a "blah" file in the current directory - instead of going to the command not found handler - it tries to execute that, and its of course not an executable script, so I get "Permission Denied"
Is there any way to trap this permission denied, like I trap the command not found? It really hits me a lot with the word "scripts" - because I like typing scripts to take me to my personal scripts directory - but every program I write also has a scripts directory in the git repo for scripts related to that repository.

Aside from removing . from your path (which you don't want to do), I don't see a way to configure zsh to avoid executing (or attempting to execute) files that match the given command in the current directory. zsh has lots of options, but I don't see documentation describing any relevant ones, nor do I see source code support for one.
I make this claim based on reading the source code for zsh's handling in the execute() function at https://sourceforge.net/p/zsh/code/ci/master/tree/Src/exec.c. Here, when zsh sees dot (.) in the path, it attempts to execute a file by that name in that directory:
for (pp = path; *pp; pp++)
if (!(*pp)[0] || ((*pp)[0] == '.' && !(*pp)[1])) {
ee = zexecve(arg0, argv, newenvp);
if (isgooderr(ee, *pp))
eno = ee;
} else {
z = buf;
strucpy(&z, *pp);
*z++ = '/';
strcpy(z, arg0);
ee = zexecve(buf, argv, newenvp);
if (isgooderr(ee, *pp))
eno = ee;
}
After that, the execute() function reaches the code below and calls zerr(), which produces the "permission denied" error message:
if (eno)
zerr("%e: %s", eno, arg0);
else if (commandnotfound(arg0, args) == 0)
_realexit();
else
zerr("command not found: %s", arg0);
... and there is no logic in the code to intercept zsh's behavior in that case.
My best suggestion to achieve the desired result is to remove dot (.) from your path.

Related

Haskell Implement Unix "touch" command

I'm trying to implement the touch command from the unix command line, but it seems that my last line throws an exception: ** Exception: ~/.todo: openFile: does not exist (No such file or directory)
main = touch "~/.todo"
touch :: FilePath -> IO ()
touch name = do
exists <- doesFileExist name
unless exists $ appendFile name ""
If there is any OS specific behavior, I'm testing from macOS Sierra.
I feel as if this error is strange in that the documentation for openFile states that
If the file does not exist and it is opened for output, it should be created as a new file.
Any suggestions as to how to fix this?
Edit: According to #chi, the touch command should always open the file, even if it already exists, because it will then update the file's last modified date.
touch :: FilePath -> IO ()
touch name = appendFile name ""
Use touchFile from the unix package (System.Posix.Files.ByteString).
appendFile name "" does not work like touch; appendFile is a no-op when the string to append is empty.
You can confirm this by running stat on the file before and after and comparing the modification times.
In the future please paste all the code you are using that creates the error. This includes both the imports and the invocation. In your case it seems you are running something with a shell expansion character:
*Main> touch "~/foobar"
*** Exception: ~/foobar: openFile: does not exist (No such file or directory)
The ~ is typically expanded by a shell (there also exists a C library that can do that rewriting for you). Most languages actually interpret that as a literal part of the path... but the ~ directory probably doesn't exist or that symbol might not even be valid depending on your platform.
Instead try a valid file path:
*Main> touch "/tmp/thisfile"
*Main>
Leaving GHCi.
% ls -l /tmp/thisfile
-rw-rw-r--. 1 theuser theuser 0 Feb 3 12:51 /tmp/thisfile

Issue in executing a batch file using PeopleCode in Application engine program

I want to execute a batch file using People code in Application Engine Program. But The program have an issue returning Exec code as a non zero value (Value - 1).
Below is people code snippet below.
Global File &FileLog;
Global string &LogFileName, &Servername, &commandline;
Local string &Footer;
If &Servername = "PSNT" Then
&ScriptName = "D: && D:\psoft\PT854\appserv\prcs\RNBatchFile.bat";
End-If;
&commandline = &ScriptName;
/* Need to commit work or Exec will fail */
CommitWork();
&ExitCode = Exec("cmd.exe /c " | &commandline, %Exec_Synchronous + %FilePath_Absolute);
If &ExitCode <> 0 Then
MessageBox(0, "", 0, 0, ("Batch File Call Failed! Exit code returned by script was " | &ExitCode));
End-If;
Any help how to resolve this issue.
Best bet is to do a trace of the execution.
Thoughts:
Can you log on the the process scheduler you are running this on and execute the script OK?
Is the AE being scheduled or called at run-time?
You should not need to change directory as you are using a fully qualified path to the script.
you should not need to call "cmd /c" as this will create an additional shell for you application to run within, making debuging harder, etc.
Run a trace, and drop us the output. :) HTH
What about changing the working directory to D: inside of the script instead? You are invoking two commands and I'm wondering what the shell is returning to exec. I'm assuming you wrote your script to give the appropriate return code and that isn't the problem.
I couldn't tell from the question text, but are you looking for a negative result, such as -1? I think return codes are usually positive. 0 for success, some other positive number for failure. Negative numbers may be acceptable, but am wondering if Exec doesn't like negative numbers?
Perhaps the PeopleCode ChDir function still works as an alternative to two commands in one line? I haven't tried it for a LONG time.
Another alternative that gives you significant control over the process is to use java.lang.Runtime.exec from PeopleCode: http://jjmpsj.blogspot.com/2010/02/exec-processes-while-controlling-stdin.html.

Debugging bitbake pkg_postinst_${PN}: Append to config-file installed by other recipe

I'm writing am openembedded/bitbake recipe for openembedded-classic. My recipe RDEPENDS on keyutils, and everything seems to work, except one thing:
I want to append a single line to the /etc/request-key.conf file installed by the keyutils package. So I added the following to my recipe:
pkg_postinst_${PN} () {
echo 'create ... more stuff ..' >> ${sysconfdir}/request-key.conf
}
However, the intended added line is missing in my resulting image.
My recipe inherits update-rc.d if that makes any difference.
My main question is: How do i debug this? Currently I am constructing an entire rootfs image, and then poke-around in that to see, if the changes show up. Surely there is a better way?
UPDATE:
Changed recipe to:
pkg_postinst_${PN} () {
echo 'create ... more stuff ...' >> ${D}${sysconfdir}/request-key.conf
}
But still no luck.
As far as I know, postinst runs at rootfs creation, and only at first boot if rootfs fails.
So there is a easy way to execute something only first boot. Just check for $D, like this:
pkg_postinst_stuff() {
#!/bin/sh -e
if [ x"$D" = "x" ]; then
# do something at first boot here
else
exit 1
fi
}
postinst scripts are ran at roots time, so ${sysconfdir} is /etc on your host. Use $D${sysconfdir} to write to the file inside the rootfs being generated.
OE-Classic is pretty ancient so you really should update to oe-core.
That said, Do postinst's run at first boot? I'm not sure. Also look in the recipes work directory in the temp directory and read the log and run files to see if there are any clues there.
One more thing. If foo RDEPENDS on bar that just means "when foo is installed, bar is also installed". I'm not sure it makes assertions about what is installed during the install phase, when your postinst is running.
If using $D doesn't fix the problem try editing your postinst to copy the existing file you're trying to edit somewhere else, so you can verify that it exists in the first place. Its possible that you're appending to a file that doesn't exist yet, and the the package that installs the file replaces it.

Has there ever been a unix system call to create a link from an open file descriptor? [duplicate]

In Unix, it's possible to create a handle to an anonymous file by, e.g., creating and opening it with creat() and then removing the directory link with unlink() - leaving you with a file with an inode and storage but no possible way to re-open it. Such files are often used as temp files (and typically this is what tmpfile() returns to you).
My question: is there any way to re-attach a file like this back into the directory structure? If you could do this it means that you could e.g. implement file writes so that the file appears atomically and fully formed. This appeals to my compulsive neatness. ;)
When poking through the relevant system call functions I expected to find a version of link() called flink() (compare with chmod()/fchmod()) but, at least on Linux this doesn't exist.
Bonus points for telling me how to create the anonymous file without briefly exposing a filename in the disk's directory structure.
A patch for a proposed Linux flink() system call was submitted several years ago, but when Linus stated "there is no way in HELL we can do this securely without major other incursions", that pretty much ended the debate on whether to add this.
Update: As of Linux 3.11, it is now possible to create a file with no directory entry using open() with the new O_TMPFILE flag, and link it into the filesystem once it is fully formed using linkat() on /proc/self/fd/fd with the AT_SYMLINK_FOLLOW flag.
The following example is provided on the open() manual page:
char path[PATH_MAX];
fd = open("/path/to/dir", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
/* File I/O on 'fd'... */
snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd);
linkat(AT_FDCWD, path, AT_FDCWD, "/path/for/file", AT_SYMLINK_FOLLOW);
Note that linkat() will not allow open files to be re-attached after the last link is removed with unlink().
My question: is there any way to re-attach a file like this back into the directory structure? If you could do this it means that you could e.g. implement file writes so that the file appears atomically and fully formed. This appeals to the my compulsive neatness. ;)
If this is your only goal, you can achieve this in a much simpler and more widely used manner. If you are outputting to a.dat:
Open a.dat.part for write.
Write your data.
Rename a.dat.part to a.dat.
I can understand wanting to be neat, but unlinking a file and relinking it just to be "neat" is kind of silly.
This question on serverfault seems to indicate that this kind of re-linking is unsafe and not supported.
Thanks to #mark4o posting about linkat(2), see his answer for details.
I wanted to give it a try to see what actually happened when trying to actually link an anonymous file back into the filesystem it is stored on. (often /tmp, e.g. for video data that firefox is playing).
As of Linux 3.16, there still appears to be no way to undelete a deleted file that's still held open. Neither AT_SYMLINK_FOLLOW nor AT_EMPTY_PATH for linkat(2) do the trick for deleted files that used to have a name, even as root.
The only alternative is tail -c +1 -f /proc/19044/fd/1 > data.recov, which makes a separate copy, and you have to kill it manually when it's done.
Here's the perl wrapper I cooked up for testing. Use strace -eopen,linkat linkat.pl - </proc/.../fd/123 newname to verify that your system still can't undelete open files. (Same applies even with sudo). Obviously you should read code you find on the Internet before running it, or use a sandboxed account.
#!/usr/bin/perl -w
# 2015 Peter Cordes <peter#cordes.ca>
# public domain. If it breaks, you get to keep both pieces. Share and enjoy
# Linux-only linkat(2) wrapper (opens "." to get a directory FD for relative paths)
if ($#ARGV != 1) {
print "wrong number of args. Usage:\n";
print "linkat old new \t# will use AT_SYMLINK_FOLLOW\n";
print "linkat - <old new\t# to use the AT_EMPTY_PATH flag (requires root, and still doesn't re-link arbitrary files)\n";
exit(1);
}
# use POSIX qw(linkat AT_EMPTY_PATH AT_SYMLINK_FOLLOW); #nope, not even POSIX linkat is there
require 'syscall.ph';
use Errno;
# /usr/include/linux/fcntl.h
# #define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
# #define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */
# #define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
unless (defined &AT_SYMLINK_NOFOLLOW) { sub AT_SYMLINK_NOFOLLOW() { 0x0100 } }
unless (defined &AT_SYMLINK_FOLLOW ) { sub AT_SYMLINK_FOLLOW () { 0x0400 } }
unless (defined &AT_EMPTY_PATH ) { sub AT_EMPTY_PATH () { 0x1000 } }
sub my_linkat ($$$$$) {
# tmp copies: perl doesn't know that the string args won't be modified.
my ($oldp, $newp, $flags) = ($_[1], $_[3], $_[4]);
return !syscall(&SYS_linkat, fileno($_[0]), $oldp, fileno($_[2]), $newp, $flags);
}
sub linkat_dotpaths ($$$) {
open(DOTFD, ".") or die "open . $!";
my $ret = my_linkat(DOTFD, $_[0], DOTFD, $_[1], $_[2]);
close DOTFD;
return $ret;
}
sub link_stdin ($) {
my ($newp, ) = #_;
open(DOTFD, ".") or die "open . $!";
my $ret = my_linkat(0, "", DOTFD, $newp, &AT_EMPTY_PATH);
close DOTFD;
return $ret;
}
sub linkat_follow_dotpaths ($$) {
return linkat_dotpaths($_[0], $_[1], &AT_SYMLINK_FOLLOW);
}
## main
my $oldp = $ARGV[0];
my $newp = $ARGV[1];
# link($oldp, $newp) or die "$!";
# my_linkat(fileno(DIRFD), $oldp, fileno(DIRFD), $newp, AT_SYMLINK_FOLLOW) or die "$!";
if ($oldp eq '-') {
print "linking stdin to '$newp'. You will get ENOENT without root (or CAP_DAC_READ_SEARCH). Even then doesn't work when links=0\n";
$ret = link_stdin( $newp );
} else {
$ret = linkat_follow_dotpaths($oldp, $newp);
}
# either way, you still can't re-link deleted files (tested Linux 3.16 and 4.2).
# print STDERR
die "error: linkat: $!.\n" . ($!{ENOENT} ? "ENOENT is the error you get when trying to re-link a deleted file\n" : '') unless $ret;
# if you want to see exactly what happened, run
# strace -eopen,linkat linkat.pl
Clearly, this is possible -- fsck does it, for example. However, fsck does it with major localized file system mojo and will clearly not be portable, nor executable as an unprivileged user. It's similar to the debugfs comment above.
Writing that flink(2) call would be an interesting exercise. As ijw points out, it would offer some advantages over current practice of temporary file renaming (rename, note, is guaranteed atomic).
Kind of late to the game but I just found http://computer-forensics.sans.org/blog/2009/01/27/recovering-open-but-unlinked-file-data which may answer the question. I haven't tested it, though, so YMMV. It looks sound.

Compile Flex application without debug? Optimisation options for flex compiler?

I have created a simple test application
with the following code
var i : int;
for (i=0; i<3000000; i++){
trace(i);
}
When I run the application, it's very slow to load, which means the "trace" is running.
I check the flash player by right-clicking, the debugger option is not enable.
So I wonder if there is an option to put in compiler to exclude the trace.
Otherwise, I have to remove manually all the trace in the program.
Are there any other options of compiler to optimize the flex application in a maximum way?
There is a really sweet feature built into Flex called the logging API (you can read more about it here http://livedocs.adobe.com/flex/3/html/logging_09.html).
Basically, you log (trace) things in a different way, admittedly with slightly more code than a standard trace, but it allows you much greater flexibility. This is an example:
import mx.logging.Log;
Log.getLogger("com.edibleCode.logDemo").info("This is some info");
Log.getLogger("com.edibleCode.logDemo").error("This is an error");
Then all you need to do is create a trace target in your main application file, something like:
<mx:TraceTarget id="logTarget" fieldSeparator=" - " includeCategory="true" includeLevel="true" includeTime="true">
<mx:filters>
<mx:Array>
<mx:String>*</mx:String>
</mx:Array>
</mx:filters>
<!--
0 = ALL, 2 = DEBUG, 4 = INFO, 6 = WARN, 8 = ERROR, 1000 = FATAL
-->
<mx:level>0</mx:level>
</mx:TraceTarget>
And register the trace with:
Log.addTarget(logTarget);
This provides several benefits over the normal trace:
You can filter (turn off) traces to only see what you want:
Either by modifying the filters array
Or the level to show only error or fatal messages
You can replace the trace target with any other type of logging interface, e.g.
A TextField
A text file
Use conditional compilation, more here.
In your code set:
CONFIG::debugging {
trace(i);
}
Then go to Project->Properties->Flex Compiler and add
-define=CONFIG::debugging,false
or
-define=CONFIG::debugging,true
You could do a find/replace on the entire project. search for 'trace(' and replace with '//trace('. That would be quick enough and easily undone.
The mxmlc argument debug allows you to add or remove debug features from SWF files. The value of the debug argument is false by default for the command line compiler, but in Flex Builder, you have to manually create a non-debug SWF. According to the documentation on compiler arguments, debug information added to the SWF includes "line numbers and filenames of all the source files". There is no mention of trace() function calls, and I don't think there's a way to remove them through a compiler argument, but you're welcome to check the linked document for the entire list of available arguments.
There are two compiler options that you should set: -debug=false -optimize=true. In Flex Builder or Eclipse, look under Project->Properties->Flex Compiler and fill in the box labeled "Additional compiler arguments."
Go to your flex code base directory (and shut down Flex Builder if its running - it gets uppity if you change things while it's running). Run this to change all your trace statements. I recommend checking the tree into git or something first and then running a diff afterwards (or cp -r the tree to do a diff -r or something). The only major case this will mess up is if you have semicolons inside trace strings:
find . -name '*.as' -exec perl -pe 'BEGIN{ undef $/; }s/trace([^;]*);/CONFIG::debugging { trace $1 ; };/smg;' -i {} \;
find . -name '*.mxml' -exec perl -pe 'BEGIN{ undef $/; }s/trace([^;]*);/CONFIG::debugging { trace $1 ; };/smg;' -i {} \;
Then set up the following in your Project->Properties->Flex Compiler->Additional compiler arguments:
-define=CONFIG::debugging,true -define=CONFIG::release,false
And use:
CONFIG::release { /* code */ }
for the "#else" clause. This was the solution I picked after reading this question and answer set.
Also beware this:
if( foo )
{
/*code*/
}
else
CONFIG::debugging { trace("whoops no braces around else-clause"); };
I.e. if you have ONLY one of these in an if or else or whatever block, and its a naked block with no braces, then regardless of whether it's compiled out, it will complain.
Something else you could do is define a boolean named debugMode or something in an external constants .as file somewhere and include this file in any project you use. Then, before any trace statement, you could check the status of this boolean first. This is similar to zdmytriv's answer.
Have to say, I like edibleCode's answer and look forward to trying it some time.

Resources