LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Blogs > rainbowsally
User Name
Password

Notices


  1. Old Comment

    More Mad Computer Science? (Simple multi-threading in a shell script)

    [My apologies to LQ if this is a duplicate post. I will create an index soon so I can consolodate these things (links instead of dups) soon.]

    To ntubski and others, a recurring theme in my posts is the ability/need for clickable scripts in linux, especially KDE and Gnome, since these are gui-based desktop managers where everything else is clickable. Therefor clickable scripts SHOULD be allowed if not expected to be written.

    Why do these linux desktops think that suddenly linux tools don't have to work "together"?

    Furthermore, the reason we can't write scripts as clickable gui apps with the default setups is unfathomable, unless they are trying to close open source themselves, which appears to be the case with the rpm/deb packages which, at least in the case of openSUSE, has binary and source packages that do NOT match!

    What gives? Doesn't that violate the open source licensing?

    Let be abuse your patience for one moment longer.

    Where's the greater threat to our 'security'? Hackers? Or unscrupulous developers.

    Think about it. And openSUSE brags about having 30,000 developers worldwide. Do we assume all of them have been vetted? They haven't even vetted their SOURCES!

    How many alleged "hackers" problems that we see in the news are in reality "inside jobs"?. Any admin already has all the access a hacker has to find by way of a security 'leak' somewhere.

    In other words, this is a BIG deal! The greater risk to the security our systems is locking us legit users OUT of our own systems.

    That said... care for a bit of mad computer science? ;-)

    This app will compile with a makefile generated by the old 'makefile-creator c launch' commandline or with 'mc2 -t c launch'. [mc2 has not been uploaded yet as of the time of this writing, Apr 5, 2012.]

    The snippets of interest here are
    • 1. the main app itself and how it closes stdout and stderr to silence the output
    • 2. usage of the fork call in case you (meaning anyone) have never tried it.
    • 3. the unparse_args() call which may be a duplicate at this blog, but can be very useful when using system() calls (which expect args in a singl string) from an argument list (of broken up strings) input to a C/C++ main() function.
      4. maintaining usage strings by way of an easily edited text file. (txt2cstr not included -- there are several utilities that can do this already).

    file: src/launch.c
    Code:
    // does execl() in a fork returning control to a terminal immediately.
    
    #include <stdio.h> // stderr
    #include <stdlib.h> // EXIT_FAILURE
    #include <unistd.h> // fork(), execl(), _exit()
    #include <sys/types.h> // pid_t
    #include "usage.str"
    #include <string.h>
    #include <malloc.h>
    #include <errno.h>
    #include "version.h"
    
    struct
    {
      char warn;
    }flg;
    
    int usage(int err);
    int unparse_args(char* cmdline, int limit, int argc, char** argv);
    int print_version(int err);
    // if error, returns argc of option to list in error display
    int parse_options(int argc, char** argv);
    
    
    int main(int argc, char** argv)
    {
      int err = 0;
      
      // help and version switches
      if(argc == 1)
        return usage(0);
      
      if(argc == 2)
      {
        if(strcmp(argv[1], "--help") == 0)
          return usage(0);
        if(strcmp(argv[1], "-v") == 0)
          return print_version(0);
      }
      
      err = parse_options(argc, argv);
      if(err) 
      {
        printf("Unknown launch option '%s'\n", argv[err]);
      }
      
      // reassemble commandline
      char args[1024];
      err = unparse_args(args, 1000, argc, argv);
      if(err)
      {
        if(err == ENOMEM)
          fprintf(stderr, "Out of memory or args list too long\n");
        else if (err == E2BIG)
          fprintf(stderr, "Argument list too long\n");
        return 1;
      }
      
      // if -q suppress all feedback from the app
      if(!flg.warn)
      {
        fclose(stdout);
        fclose(stderr);
        strcat(args, " > /dev/null 2>&1");
      }
      
      // do the fork and execute the commandline
      pid_t pid;
      
      pid = fork ();
      if (pid == 0)
      {
        
        
        // command path, command name, arg1, arg2, ...
        execl ("/bin/sh", "sh", "-c", args, NULL);
        
        // _exit(code) for threads and forks.
        _exit (EXIT_FAILURE);
      }
      else if (pid < 0)
        return -1;
      else
        return 0;
    }
    
    
    int usage(int err)
    {
      if(err)
        fprintf(stderr, "%s", usage_str);
      else
        fprintf(stdout, "%s", usage_str);
      return err;
    }
    
    // returns 0 on success, or one of the following
    // #define ENOMEM    12  /* Out of memory */
    // #define E2BIG    7  /* Argument list too long */
    // defined in /usr/include/asm-generic/errno-base.h
    
    int unparse_args(char* cmdline, int limit, int argc, char** argv)
    {
      cmdline[0] = 0;
      if(argc < 2)
        return 0;
      
      char* buf = (char*) malloc(limit+256);
      if(!buf)
        return errno = ENOMEM;
      
      char* p = buf;
      char* stopat = buf+limit -1;
      int len;
      
      // point to args list
      argc --;
      argv ++;
      
      // skip option switches
      if(flg.warn)
      {
        argc --;
        argv ++;
      }
      
      //////////////////////////////////////
      // recreate command and commandline
      //////////////////////////////////////
      
      for(int i = 0; i < argc; i++)
      {
        p += sprintf(p, "%s ", argv[i]);
        if(p >= stopat)
        {
          free(buf);
          return errno = E2BIG;
        }
      }
      p[-1] = 0; // terminate
      memcpy(cmdline, buf, p-buf);
      free(buf);
      return 0;
    }
    
    int print_version(int err)
    {
      printf("Launch version %s\n", VERSION);
      return err;
    }
    
    int parse_options(int argc, char** argv)
    {
      // if no options, return
      if(argv[1][0] != '-')
        return 0;
      
      // init opts
        flg.warn = 0; // default
        
        // check args (only 1 so far)
        int arg = 1;
        
        // assume error each iteration
        int err = 1;
        
        // check and break if match
        if(strcmp(argv[arg], "-a") == 0)    
        { 
          flg.warn = 1;
          err = 0;
        }
        
        // return argN where error occurred or 0
        if(err) 
          return arg;
        else 
          return 0;
    }
    file: src/update-strings.exec (executable)
    [Note: in kde this is clickable, just click on it and it's done.]
    Code:
    #!/bin/sh
    cd `dirname "$0"`
    printf "" >.msg
    txt2str usage.txt usage_str usage.str 2>>.msg
    echo 'done.' >> .msg
    kdialog --msgbox "$(<.msg)"
    rm -f .msg
    file: src/usage.str
    Code:
    /* usage.txt converted with txt2cstr */
    const char* usage_str =
    "\n"
    "Usage launch [opt] <command> [parameters]\n"
    "\n"
    "Launch just returns control to the terminal immediately after \n"
    "starting an app.  Useful for launching one or more other \n"
    "applications while retaining ability to use the terminal.\n"
    "\n"
    "Options for launch must preceed the command and it's arguments.\n"
    "\n"
    "Recognized optiions are:\n"
    "  --help          this display\n"
    "  -v              version\n"
    "  -a              allow feedback from the launched app.\n"
    "\n"
    ;
    file: src/usage.txt
    Code:
    Usage launch [opt] <command> [parameters]
    
    Launch just returns control to the terminal immediately after 
    starting an app.  Useful for launching one or more other 
    applications while retaining ability to use the terminal.
    
    Options for launch must preceed the command and it's arguments.
    
    Recognized optiions are:
    --help          this display
    -v              version
    -a              allow feedback from the launched app.
    file: src/version.h
    Code:
    // initial version
    // #define VERSION "1.0"
    
    // changed switch to -w to allow warnings to display.  Defaults to
    // supress warnings and other feedback from launched applications.
    // #define VERSION "1.1"
    
    // Added these notes in the version header.
    // #define VERSION "1.2"
    
    // Can't just close stdout or kde will spin out.  Trying redirect
    // to /dev/null for kde and also closing stdin and stderr to -1
    // for normal user.
    // #define VERSION "1.3"
    
    // Changing switch to -a for 'allow' error and warnings instead
    // of -w, which might be useful for a windows style /w(ait) 
    // if anyone uses this for a 'start' clone.
    // #define VERSION "1.4"
    
    // Release .1 corrects a misspelling in this file.
    #define VERSION "1.4.1"
    Thanks for the blog, LQ.

    :-)
    Posted 04-05-2012 at 06:49 PM by rainbowsally rainbowsally is offline
  2. Old Comment

    More Mad Computer Science? (Simple multi-threading in a shell script)

    ntubski,

    I apologize here. I forgot I was using the nohup version of this app.

    I did try what you suggested, by the way, but for some reason in kde it wouldn't work. Possibly lost something in the environment? Dunno.

    I personally use a C based version of launch, which can be expanded to behave like a Windows 'start' app if one wanted to do that (probably using xdg-mime query filetype or something).

    I use Windows for my dialup modem driver so I'll post the C version in the next comment.

    Whether these things are 'necessary' or not, they may be interesting. If you discover a way to optimize the process, great. But running nohup from the script when clicked on doesn't work.

    Here comes the C version... (Give me a few minutes... to go into my linux partition and get it.)

    :-)
    Posted 04-05-2012 at 05:46 PM by rainbowsally rainbowsally is offline
  3. Old Comment

    More Mad Computer Science? (Simple multi-threading in a shell script)

    nohup is close. The 50K nohup program does essentially the same thing (as does kshell).

    Try it and see. (Remember the app is clickable.)
    Posted 04-05-2012 at 05:24 PM by rainbowsally rainbowsally is offline
    Updated 04-05-2012 at 05:28 PM by rainbowsally
  4. Old Comment

    C/C++ dosex (irregular expressions :) for copying, renaming with wildcards

    So DOS has a replace strings with wildcards? How does it work?
    Posted 04-05-2012 at 09:30 AM by ntubski ntubski is offline
  5. Old Comment

    C/C++ dosex (irregular expressions :) for copying, renaming with wildcards

    Glob doesn't work for 'replace' strings. Or if it does, I've never seen it done.
    Posted 04-05-2012 at 08:49 AM by rainbowsally rainbowsally is offline
  6. Old Comment
    Posted 04-02-2012 at 09:53 PM by ntubski ntubski is offline
  7. Old Comment

    More Mad Computer Science? (Simple multi-threading in a shell script)

    All these advantages you list come from using 'nohup', right? That is, putting
    Code:
    nohup kdialog -passivepopup "$msg" 3 >/dev/null 2>&1 &
    instead of
    Code:
    ~/.launcher kdialog -passivepopup "$msg" 3
    would give the same results.

    If I understand correctly, creating the new program is just a way of factoring out the repeated nohup command. In that case I would suggest using a function instead:
    Code:
    launcher()
    {
        nohup "$@" >/dev/null 2>&1 &
    }
    ...
    launcher kdialog -passivepopup "$msg" 3
    This has the advantage that if you run multiple launchers, they won't step on each other.

    PS you're right, I'm not a KDE user.
    Posted 04-02-2012 at 09:03 PM by ntubski ntubski is offline
  8. Old Comment

    More Mad Computer Science? (Simple multi-threading in a shell script)

    The advantages are many.

    One is that you get a new window with a new app without the TONS of commandline noise you get with, say KDE.

    I expect you are not a KDE user.

    Also, this is a way to run apps with 'init' as the parent, independent of the existence of the terminal. Close the terminal and the window remains open. Useful for stuff like opening docs that you can only access by way of the commandline. Open a terminal, launch the docs (/kdevelop man: find', for example) and get rid of the terminal.

    In this example, we just see that it can be done by creating a program with another program.

    Exploring the potentials of linux, you might say.

    This can NOT be done in Windows.

    Thanks for the question.
    Posted 03-31-2012 at 03:58 AM by rainbowsally rainbowsally is offline
  9. Old Comment
    Posted 03-31-2012 at 03:38 AM by rainbowsally rainbowsally is offline
  10. Old Comment

    Simple C: Beyond Bash Part 1 - String lists and pipes

    For a straight shell script you're right.

    Thanks for the comment. :-)
    Posted 02-11-2012 at 11:11 AM by rainbowsally rainbowsally is offline
  11. Old Comment

    Simple C: Beyond Bash Part 1 - String lists and pipes

    Code:
    OBJ=`ls *.o` # Think about this.  :-)  Automatic object listing.
    echo $OBJ # and verify that main.o and slist.o are both compiled.
    Don't parse ls:

    Code:
    OBJ=*.o
    echo $OBJ
    Posted 02-04-2012 at 09:34 PM by ntubski ntubski is offline
  12. Old Comment

    Frankenstein (bash) Meets GodziRRa (C/C++).

    You shouldn't assume "." is in $PATH.
    Code:
    # run it with a valid input param so it doesn't crash.
    # we know file-sig will exist so let's do that again.
    ./file-sig file-sig
    Posted 02-04-2012 at 09:24 PM by ntubski ntubski is offline
  13. Old Comment

    Simple C: Filling in the blanks - A simple memory allocator/reallocator.

    Code:
    // NOTE:
    // Since C++ syntax is so strict we can create aliases that will cast the
    // input params to the type needed by the functions.  This is a little risky 
    // because even 'longs' can be case to char**, and crazy stuff like that...
    You could use a template function to accept only pointer types:
    Code:
    #ifdef __cplusplus
    template<typename T, typename U>
    inline void memcat(T** dest, int* destsize, const U* src, int srcsize)
    {
       _memcat((void**)dest, destsize, (const void*)src, srcsize)
    }
    #else
    #define memcat(dest, destsize, src, srcsize) _memcat(dest, destsize, src, srcsize)
    #endif
    Posted 02-04-2012 at 09:18 PM by ntubski ntubski is offline
  14. Old Comment

    More Mad Computer Science? (Simple multi-threading in a shell script)

    I don't follow what the advantage in making a separate launcher file is?
    Posted 02-04-2012 at 07:37 PM by ntubski ntubski is offline
  15. Old Comment

    Computer Mad Science: Classic Style KDE Menu (Shows That We CAN...)

    For what it's worth, KAlgebra is a very nice application and does somewhat the same thing XMaxima does, but it just feels like peeking through a keyhole compared to XMaxima. At least to me, it does.

    XMaxima is RETRO! But it's an outstanding piece of software.

    It's complicated to compile (due to depenedencies that are also now supposedly obsolete) so that may not be what I end up using as an example of how to get these things to show in the menus correctly.

    But I'll post something, provided the winds remain favorable.

    Stay tuned. :-)
    Posted 01-20-2012 at 03:46 AM by rainbowsally rainbowsally is offline
    Updated 01-20-2012 at 03:48 AM by rainbowsally
  16. Old Comment

    KDE Utils: new.symlink, launch, edit, browse, tofile

    ---------------------------------------
    File: tofile (compiled)
    Path: HOME/bin/src/tofile-2.0
    Purpose: A way to capture and view output from linux commands (instead of 'more')
    Compile: 'gcc tofile.cpp -o tofile'
    Link: n/a

    [This is a C/C++ program. You may want it as a bash script but bash is so difficult to figure at times that the C was a lot more sensible, at least for me.]

    Install and uninstall as above.

    This (as is edit) are dependent on kate. Kwrite won't work as well for the edit utility (e.g., line number parsing last time I checked) but if you want to you can easily modify this to your own liking even if you don't know a lot of (read "any") C/C++, but I'll let you experiment with the code on your own.

    If you do want to experiment, find 'edit' in the main file below. That's where you can modify the program used to view the document. But change the version number to your own just for kicks. ;-)

    Here are the sources included in the main file.

    File: version.h
    Code:
    // rewrote in C/C++ to give more control over how strings are interpreted
    #define VERSION "2.0"
    File: usage.str
    Code:
    /* usage_str.txt converted with txt2cstr */
    const char* usage_str =
        "\n"
        "Usage: tofile <command> [args]\n"
        "\n"
        "  Sends output of command and args to a file and opens it\n"
        "  in an editor named 'edit', expected to be found in the\n"
        "  user's current PATH.\n"
        "\n"
        "  The following switches may replace <command>\n"
        "\n"
        "    --help            print this message\n"
        "    -v | --version    print version info\n"
        "\n"
        ;
    And here's the main file.

    File: tofile.cpp
    Code:
    // tofile - sends commandline results to file and opens in an editor
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h> // getenv()
    #include "usage.str"
    #include "version.h"
    
    #define streq(a, b) (strcmp(a, b) == 0)
    
    void dbg(){}
    
    int do_pipe(const char* filename, char* cmdline);
    int usage(int err);
    int print_version(int err);
    
    int main(int argc, char** argv)
    {
      dbg();
      
      int err = 0;
      
      char cmdline[256];
      char* p = cmdline;
      
      char filename[256];
      sprintf(filename, "%s/tofile.tmp", getenv("HOME"));
      // usage notes
      if(argc < 2)
        return usage(1);
      
      if(streq(argv[1], "--help"))
         return usage(0);
      
      if(streq(argv[1], "-v") || streq(argv[1], "--version"))
        return print_version(0);
    
      if(argc > 16)
      {
        fprintf(stderr, "Too many args. Did you use a splat in an unquoted args list?\n");
        return 1;
      }
      
      // reassemble commandline
      for(int i = 1; i < argc; i++)
        p += sprintf(p, "%s ", argv[i]);
      
      p[-1] = 0;
      
      // pipe the commandline to ~/tofile.tmp
      err = do_pipe(filename, cmdline);
      if(err)
      {
        fprintf(stderr, "\n  Error reading piped command\n\n");
        return 1;
      }
      
      // try some other editors with the output file.  I prefer 'edit'. -rs
      sprintf(cmdline, "edit %s/tofile.tmp", getenv("HOME"));
      return system(cmdline);
    }
    
    
    int usage(int errcode)
    {
      printf("%s", usage_str);
      return errcode;
    }
    
    int do_pipe(const char* filename, char* cmdline)
    {
      int nbytes;
      char buf[4096];
      FILE* outfile = fopen(filename, "wb");
      if(!outfile)
        return 1;
      
      FILE* infile = popen(cmdline, "r");
      if(!infile)
        return 1;
      
      while(!feof(infile))
      {
        *buf = 0;
        nbytes = fread(buf, 1, 4096, infile);
        fwrite(buf, 1, nbytes, outfile);
      }
      fflush(outfile);
      fclose(infile);
      fclose(outfile);
      return 0;
    }
    
    int print_version(int errcode)
    {
      printf("%s\n", VERSION);
      return errcode;
    }
    To test try this:

    Code:
    tofile grep "a" "~/bin/*"
    That will find all occurances of the letter a in the utilities created so far.

    Try it without the quotes around the splatted argument and see what happens.

    For something a bit more useful, try this.

    Code:
    tofile cat --help
    Other helps can be viewed the same way and the terminal is immediately free to use even while the help file is open.

    We'll look at a prettier help viewer in a bit but this is a good example of how we can customize our systems to get the best of linux and kde, working together to produce some common sense tools that do more and/or do it better than either one did before.
    Posted 01-16-2012 at 01:51 PM by rainbowsally rainbowsally is offline

  



All times are GMT -5. The time now is 12:19 AM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration