"Fossies" - the Fresh Open Source Software Archive

Member "unipkg-0.6.5/unipkglib/unipkg-slack.c" (16 Dec 2005, 50808 Bytes) of package /linux/privat/old/unipkg-0.6.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /******************************************************************************\
    2 *                                                                              *
    3 * UNIPKG (c) iSteve <isteve@bofh.cz>, 2005                                     *
    4 *                                                                              *
    5 * Universal PacKaGer.                                                          *
    6 * Licensed under GNU/GPL - if you don't like the software, fix it!             *
    7 *                                                                              *
    8 \******************************************************************************/
    9 
   10 ///////////////////////////////////////////////////////////////////////////////
   11 //                                                                           //
   12 // B A S E   I N C L U S I O N S   A N D   D E F I N I T I O N S             //
   13 //                                                                           //
   14 ///////////////////////////////////////////////////////////////////////////////
   15 #define _GNU_SOURCE
   16 #include <stdlib.h>
   17 #include <stdio.h>
   18 #include <string.h>
   19 #include <unistd.h>
   20 #include <fcntl.h>
   21 
   22 #include <ctype.h>
   23 #include <libgen.h>
   24 
   25 #include <sys/types.h>
   26 #include <sys/mman.h>
   27 #include <sys/stat.h>
   28 
   29 #ifdef HAVE_SYSMACROS_H
   30 #include <sys/sysmacros.h>
   31 #endif
   32 
   33 #include <errno.h>
   34 
   35 #include <zlib.h>
   36 
   37 #include "../archive.h"
   38 #include "../compression.h"
   39 #include "../common.h"
   40 
   41 // Decide on slack parser to be used //////////////////////////////////////////
   42 #define SLACK_COMPLEX
   43 ///////////////////////////////////////////////////////////////////////////////
   44 
   45 // Shell parsing definitions //////////////////////////////////////////////////
   46 #define PNONE       0
   47 #define FLAG        1
   48 #define DATA        2
   49 #define PMASK       3       // Mask for all base pstatus stuff
   50 
   51 #define PNOFLAG     4       // This is sort of extra
   52 
   53 #define QNONE       8
   54 #define QSINGLE     16
   55 #define QDOUBLE     32
   56 #define QMAKS       56
   57 
   58 #define QSUBSHELL   64
   59 
   60 #define NODATA      0
   61 #define SPACEDATA   1
   62 #define EQUIDATA    2
   63 
   64 #define SHORTOPT    0
   65 #define LONGOPT     1
   66 
   67 #define NONFREE(ptr)    ((*ptr != ' ') && (*ptr != '\t') && (*ptr != '\n') && (*ptr != ';'))
   68 
   69 #define SCLEAR      0
   70 #define SBLOCK      1
   71 
   72 typedef struct {
   73     char        **names;
   74     unsigned long   count;
   75 } shellbuiltins;
   76 
   77 typedef struct {
   78     char        *flag;              // like --suffix= ...
   79     unsigned long   flaglen;
   80     int     data;
   81     int     type;               // short, long
   82 } paramflag;
   83 
   84 typedef struct {
   85     char        *content;
   86     int     id;                 // -1 if ordinary data, 0+ if some flag
   87 } outformat;
   88 
   89 typedef struct {
   90     char        *fbase;             // Such as 'ln '.
   91     int     magic;              // For further use
   92     
   93     unsigned long   outcount, flagcount;
   94     
   95     outformat   *outputs;
   96     paramflag   *flags;
   97 } funcdef;
   98 
   99 typedef struct {
  100     char        *pwd;
  101     int     status;
  102 } subshell;
  103 ///////////////////////////////////////////////////////////////////////////////
  104 
  105 // Trivial parser definitions /////////////////////////////////////////////////
  106 #ifndef SLACK_COMPLEX
  107 typedef struct {
  108     char        *linkfile;
  109     char        *target;
  110 } linkinfo;
  111 #endif
  112 ///////////////////////////////////////////////////////////////////////////////
  113 
  114 ///////////////////////////////////////////////////////////////////////////////
  115 //                                                                           //
  116 // B A S E   F U N C T I O N S                                               //
  117 //                                                                           //
  118 ///////////////////////////////////////////////////////////////////////////////
  119     
  120 // SWITCH_CONTROL_NAMES()
  121 //
  122 // Identifies the filename as member of install folder
  123 //
  124 // Parameters:
  125 //   the path
  126 //
  127 // Return value:
  128 //   0 if doinst.sh
  129 //   1 if slack-desc
  130 //   -1 if error
  131 static int switch_control_names(char *fn) {
  132     if ((!strcmp(fn, "./install/doinst.sh")) || (!strcmp(fn, "install/doinst.sh"))) { return 0; }
  133     if ((!strcmp(fn, "./install/slack-desc")) || (!strcmp(fn, "install/slack-desc"))) { return 1; }
  134     
  135     return -1;
  136 }
  137 
  138 ///////////////////////////////////////////////////////////////////////////////
  139 
  140 #ifdef SLACK_COMPLEX
  141 ///////////////////////////////////////////////////////////////////////////////
  142 //                                                                           //
  143 // C O M P L E X   S H E L L   S E M I P A R S I N G                         //
  144 //                                                                           //
  145 ///////////////////////////////////////////////////////////////////////////////
  146 
  147 // SWITCH_NODATA_OPTIONS()
  148 //
  149 // Checks if needle is a flag, which takes no additional data, as defined in fdef.
  150 //
  151 // Parameters:
  152 //   needle
  153 //   pointer to function definition
  154 //
  155 // Return value:
  156 //   0 if no match
  157 //   id of the flag otherwise
  158 int switch_nodata_options(char *ptr, funcdef *fdef) {
  159     unsigned long   i;
  160     
  161     for (i=0; i < fdef->flagcount; i++) {
  162         if (fdef->flags[i].data == NODATA) {
  163             if (!strcmp(ptr, fdef->flags[i].flag)) {
  164                 return i+1;
  165             }
  166         }
  167     }
  168     
  169     return 0;
  170 }
  171 
  172 // SWITCH_DATA_OPTIONS()
  173 //
  174 // Checks if needle is a flag, which takes some additional data, as defined in fdef.
  175 //
  176 // Parameters:
  177 //   needle
  178 //   pointer to function definition
  179 //
  180 // Return value:
  181 //   0 if no match
  182 //   id of the flag otherwise
  183 int switch_data_options(char *ptr, funcdef *fdef) {
  184     unsigned long   i;
  185     
  186     for (i=0; i < fdef->flagcount; i++) {
  187         if (fdef->flags[i].data == SPACEDATA) {
  188             if (!strcmp(ptr, fdef->flags[i].flag)) {  return i+1; }
  189         }
  190         if (fdef->flags[i].data == EQUIDATA) {
  191             if (!strncmp(ptr, fdef->flags[i].flag, fdef->flags[i].flaglen)) {  return i+1; }
  192         }
  193     }
  194     
  195     return 0;
  196 }
  197 
  198 // counts on shortops grouped are oneletter ... but what else would they be?
  199 // SEPARATE_SHORTOPTS()
  200 //
  201 // Separates grouped short options, only last may take option
  202 //
  203 // Parameters:
  204 //   needle
  205 //   pointer to function definition
  206 //
  207 // Return value:
  208 //   0 if no match
  209 //   1 if one or more matches
  210 //   -1 if one or more matches, while the last takes data
  211 static int separate_shortopts(char *ptr, funcdef *fdef) {
  212     unsigned long   i;
  213     char        tmpbuf[3];
  214     int     reval, retval;
  215     
  216     ptr++;          // skip heading '-'
  217     
  218     tmpbuf[0] = '-';
  219     tmpbuf[2] = '\0';
  220     retval = 0;
  221     while (*ptr != '\0') {
  222         for (i=0; i < fdef->flagcount; i++) {
  223             if ((fdef->flags[i].type == SHORTOPT) && (fdef->flags[i].data == NODATA)) {
  224                 tmpbuf[1] = *ptr;
  225                 if (!strcmp(tmpbuf, fdef->flags[i].flag)) {
  226                     retval=1;
  227                     fdef->outputs[fdef->outcount].content = strdup("");
  228                     fdef->outputs[fdef->outcount].id = i;
  229                     fdef->outcount++;
  230                     fdef->outputs = realloc(fdef->outputs, sizeof(outformat) * (fdef->outcount + 1));
  231                 }
  232             }
  233         }
  234         ptr++;
  235     }
  236     
  237     if ((reval = switch_data_options(tmpbuf, fdef)) != 0) {
  238         return reval;
  239     } else {
  240         return -retval;
  241     }
  242 }
  243 
  244 // ADDCHAR()
  245 //
  246 // Adds a character to pos in a buffer sized len, enlarges it by if needed.
  247 //
  248 // Parameters:
  249 //   pointer to (pointer to) the buffer
  250 //   size of buffer
  251 //   pointer to index of current position in buffer
  252 //   character added
  253 //
  254 // Return value:
  255 //   new size of buffer
  256 static unsigned long addchar(char **buf, unsigned long len, unsigned long *pos, char c) {
  257     if (len <= *pos) {
  258         len = *pos * 2;
  259         *buf = realloc(*buf, len + 1);
  260     }
  261     (*buf)[*pos] = c;
  262     (*pos)++;
  263     return len;
  264 }
  265 
  266 // ADDOUTPUT()
  267 //
  268 // Adds another data parameter.
  269 //
  270 // Parameters:
  271 //   pointer to function definition
  272 //   string added
  273 //   type of data
  274 //
  275 // Return value:
  276 //   none
  277 static void addoutput(funcdef *fdef, char *s, int type) {
  278     fdef->outputs[fdef->outcount].content = strdup(s);
  279     fdef->outputs[fdef->outcount].id = type;
  280     fdef->outcount++;
  281     fdef->outputs = realloc(fdef->outputs, sizeof(outformat) * (fdef->outcount + 1));
  282 }
  283 
  284 // PARSECOMMAND()
  285 //
  286 // A rather complex function, which parses the whole function call more or less
  287 // like POSIX compliant shell would. It's black magic, fear and tremble.
  288 //
  289 // Parameters:
  290 //   string we parse
  291 //   pointer which sets the end of string
  292 //   pointer to pointer to end of parsing
  293 //   pointer to function definition for which we parse
  294 //
  295 // Return value:
  296 //   always 0
  297 static int parsecommand(char *ptr, char *eptr, char **fptr, funcdef *fdef) {    
  298     int     pstatus, qstatus, ctype;
  299     // pstatus tells us about how parsing goes
  300     // qstatus is for data and tells us status of quotes
  301     // ctype contains information about data type, -2 uninteresting, -1 data, 0+ flag
  302     
  303     unsigned long   curlen, curpos;
  304     int     reval;
  305     char        *buf;
  306     
  307     ptr += strlen(fdef->fbase); // skip "ln"
  308     while ((isspace(*ptr)) && (*ptr != '\0')  && (*ptr != '\n')) {
  309         ptr++;                  // We can't have "ln--flag", we have to separate it ... by a freespace;
  310     }
  311     *fptr = ptr;
  312     
  313     pstatus = DATA;
  314     qstatus = QNONE;
  315     
  316     curlen = 0;
  317     curpos = 0;
  318     buf = malloc(1);
  319     
  320     ctype = -1;
  321     
  322     while (*ptr != '\0') {
  323         switch (*ptr) {
  324             case '\\':
  325                 switch (qstatus) {
  326                     case QNONE:
  327                         ptr++;
  328                         curlen = addchar(&buf, curlen, &curpos, *ptr);
  329                         break;
  330                     case QSINGLE:
  331                         curlen = addchar(&buf, curlen, &curpos, *ptr);
  332                         break;
  333                     case QDOUBLE:
  334                         ptr++;
  335                         switch (*ptr) {
  336                             case 'a':   curlen = addchar(&buf, curlen, &curpos, '\a');
  337                                 break;
  338                             case 'b':   curlen = addchar(&buf, curlen, &curpos, '\b');
  339                                 break;
  340                             case 'f':   curlen = addchar(&buf, curlen, &curpos, '\f');
  341                                 break;
  342                             case 'n':   curlen = addchar(&buf, curlen, &curpos, '\n');
  343                                 break;
  344                             case 'r':   curlen = addchar(&buf, curlen, &curpos, '\r');
  345                                 break;
  346                             case 't':   curlen = addchar(&buf, curlen, &curpos, '\t');
  347                                 break;
  348                             case 'v':   curlen = addchar(&buf, curlen, &curpos, '\v');
  349                                 break;
  350                             default: 
  351                                 curlen = addchar(&buf, curlen, &curpos, *ptr);
  352                                 break;
  353                         }
  354                         break;
  355                 }
  356                 break;
  357             case '\'':
  358                 switch (qstatus) {
  359                     case QNONE:
  360                         qstatus = QSINGLE;
  361                         break;
  362                     case QSINGLE:
  363                         qstatus = QNONE;
  364                         break;
  365                     case QDOUBLE:
  366                         curlen = addchar(&buf, curlen, &curpos, *ptr);
  367                         break;
  368                 }
  369                 break;
  370             case '"':
  371                 switch (qstatus) {
  372                     case QNONE:
  373                         qstatus = QDOUBLE;
  374                         break;
  375                     case QSINGLE:
  376                         curlen = addchar(&buf, curlen, &curpos, *ptr);
  377                         break;
  378                     case QDOUBLE:
  379                         qstatus = QNONE;
  380                         break;
  381                 }
  382                 break;
  383             case '\t':
  384             case ' ':
  385                 if (qstatus == QNONE) {     // Terminate, we found end of data  
  386                     curlen = addchar(&buf, curlen, &curpos, '\0');
  387                     if ((pstatus != PNOFLAG) && (!strcmp(buf, "--"))) { 
  388                         pstatus = PNOFLAG; 
  389                     } else {
  390                         if ((pstatus != PNOFLAG) && ((reval = switch_data_options(buf, fdef)) != 0)) {
  391                             ctype = reval-1;
  392                             if (fdef->flags[ctype].data == EQUIDATA) {                                      
  393                                 addoutput(fdef, buf + fdef->flags[ctype].flaglen, ctype);
  394                                 ctype = -1;
  395                             }
  396                         } else {
  397                             if (ctype != -1) {
  398                                 addoutput(fdef, buf, ctype);
  399                                 ctype = -1;
  400                             } else {
  401                                 if ((pstatus != PNOFLAG) && ((reval = switch_nodata_options(buf, fdef)) != 0)) {
  402                                     ctype = reval-1;
  403                                     addoutput(fdef, "", ctype);
  404                                     ctype = -1;
  405                                 } else {
  406                                     if ((pstatus != PNOFLAG) && (strlen(buf)>=3) && (buf[0] == '-') && (buf[1] != '-'))  {
  407                                         reval = separate_shortopts(buf, fdef);
  408                                         if (reval > 0) {
  409                                             ctype = reval - 1;
  410                                         } else { 
  411                                             ctype = -1;
  412 
  413                                             if (!((pstatus == PNOFLAG) && (buf[0] == '-')) && (reval == 0)) {
  414                                                 addoutput(fdef, buf, ctype);
  415                                             }
  416                                         }
  417                                     } else {
  418                                         ctype = -1;
  419                                         if (!((pstatus == PNOFLAG) && (buf[0] == '-'))) {
  420                                             addoutput(fdef, buf, ctype);
  421                                         }
  422                                     }
  423                                 }
  424                             }
  425                         }
  426                     }
  427                     
  428                     curlen = 0;
  429                     curpos = 0;
  430                     buf = realloc(buf, 1);
  431                     
  432                     pstatus = PNONE | (pstatus & PNOFLAG);
  433                     
  434                     while ((!isspace(*ptr)) && (ptr < eptr)) {
  435                         ptr++;
  436                     }
  437                 } else {                        // continue
  438                     curlen = addchar(&buf, curlen, &curpos, *ptr);
  439                 }
  440                 break;
  441             case '&':
  442                 if (*(ptr+1) != '&') {
  443                     curlen = addchar(&buf, curlen, &curpos, *ptr);
  444                     break;
  445                 } else {
  446                     free(buf);
  447                     ptr--;
  448                     *fptr = ptr;
  449                     return 0;
  450                 }
  451             case '|':
  452                 if (*(ptr+1) != '|') {
  453                     curlen = addchar(&buf, curlen, &curpos, *ptr);
  454                     break;
  455                 } else {
  456                     free(buf);
  457                     ptr--;
  458                     *fptr = ptr;
  459                     return 0;
  460                 }
  461             case '\0':      // To ensure this is parsed fine...
  462                 qstatus = QNONE;
  463             case '`':       // This is questionable
  464             case ')':       // So are the subshells
  465             case '(':       // On the other hand, this
  466             case '}':       // is still meant to be rather
  467             case '{':       // simple parser, so it shouldn't
  468             case ';':       // matter much.
  469             case '\n':      // newline, on the other hand, is mandatory
  470                 if (qstatus == QNONE) {
  471                     curlen = addchar(&buf, curlen, &curpos, '\0');
  472                     
  473                     if ((pstatus != PNOFLAG) && (!strcmp(buf, "--"))) { 
  474                         pstatus = PNOFLAG; 
  475                     } else {
  476                         if ((pstatus != PNOFLAG) && ((reval = switch_data_options(buf, fdef)) != 0)) {
  477                             ctype = reval-1;
  478                             if (fdef->flags[ctype].data == EQUIDATA) {                                      
  479                                 addoutput(fdef, buf + fdef->flags[ctype].flaglen, ctype);
  480                                 ctype = -1;
  481                             }
  482                         } else {
  483                             if (ctype != -1) {
  484                                 addoutput(fdef, buf, ctype);
  485                                 ctype = -1;
  486                             } else {
  487                                 if ((pstatus != PNOFLAG) && ((reval = switch_nodata_options(buf, fdef)) != 0)) {
  488                                     ctype = reval-1;
  489                                     addoutput(fdef, "", ctype);
  490                                     ctype = -1;
  491                                 } else {
  492                                     if ((pstatus != PNOFLAG) && (strlen(buf)>=3) && (buf[0] == '-') && (buf[1] != '-'))  {
  493                                         reval = separate_shortopts(buf, fdef);
  494                                         if (reval > 0) {
  495                                             ctype = reval - 1;
  496                                         } else { 
  497                                             ctype = -1;
  498                                             if (!((pstatus == PNOFLAG) && (buf[0] == '-')) && (reval == 0)) {
  499                                                 addoutput(fdef, buf, ctype);
  500                                             }
  501                                         }
  502                                     } else {
  503                                         ctype = -1;
  504                                         if (!((pstatus == PNOFLAG) && (buf[0] == '-'))) {
  505                                             addoutput(fdef, buf, ctype);
  506                                         }
  507                                     }
  508                                 }
  509                             }
  510                         }
  511                     }
  512                     
  513                     // We've reached end of function, let's drop out.
  514                     free(buf);
  515                     ptr--;  // not to waste the character we currently consider terminating -- it may be parsed outside
  516                     *fptr = ptr;
  517                     return 0;
  518                     // And drop out we did.
  519                 } else {
  520                     curlen = addchar(&buf, curlen, &curpos, *ptr);
  521                 }
  522                 break;
  523             default:
  524                 curlen = addchar(&buf, curlen, &curpos, *ptr);
  525                 break;
  526         }
  527         ptr++;
  528     }
  529     
  530     // cleanups
  531     if (curlen > 0) {
  532         curlen = addchar(&buf, curlen, &curpos, '\0');
  533         if ((pstatus != PNOFLAG) && (!strcmp(buf, "--"))) { 
  534             pstatus = PNOFLAG; 
  535         } else {
  536             if ((pstatus != PNOFLAG) && ((reval = switch_data_options(buf, fdef)) != 0)) {
  537                 ctype = reval-1;
  538                 if (fdef->flags[ctype].data == EQUIDATA) {                                      
  539                     addoutput(fdef, buf + fdef->flags[ctype].flaglen, ctype);
  540                     ctype = -1;
  541                 }
  542             } else {
  543                 if (ctype != -1) {
  544                     addoutput(fdef, buf, ctype);
  545                     ctype = -1;
  546                 } else {
  547                     if ((pstatus != PNOFLAG) && ((reval = switch_nodata_options(buf, fdef)) != 0)) {
  548                         ctype = reval-1;
  549                         addoutput(fdef, "", ctype);
  550                     } else {
  551                         if ((pstatus != PNOFLAG) && (strlen(buf)>=3) && (buf[0] == '-') && (buf[1] != '-'))  {
  552                             reval = separate_shortopts(buf, fdef);
  553                             if (reval > 0) {
  554                                 ctype = reval - 1;
  555                             } else { 
  556                                 ctype = -1;
  557                                 if (!((pstatus == PNOFLAG) && (buf[0] == '-')) && (reval == 0)) {
  558                                     addoutput(fdef, buf, ctype);
  559                                 }
  560                             }
  561                         } else {
  562                             ctype = -1;
  563                             if (!((pstatus == PNOFLAG) && (buf[0] == '-'))) {
  564                                 addoutput(fdef, buf, ctype);
  565                             }
  566                         }
  567                     }
  568                 }
  569             }
  570         }
  571     }
  572     
  573     *fptr = ptr;
  574 
  575     curlen = addchar(&buf, curlen, &curpos, '\0');
  576 
  577     free(buf);
  578     
  579     return 0;
  580 }
  581 
  582 // ADDFLAG()
  583 //
  584 // Adds another flag definition to function definition.
  585 //
  586 // Parameters:
  587 //   pointer to function definition
  588 //   flag added
  589 //   type of data obtained
  590 //   type (id) of flag
  591 //
  592 // Return value:
  593 //   none
  594 static void addflag(funcdef *fdef, char *flag, int data, int type) {
  595     fdef->flags[fdef->flagcount].flag = strdup(flag);
  596     fdef->flags[fdef->flagcount].flaglen = strlen(flag);
  597     fdef->flags[fdef->flagcount].data = data;
  598     fdef->flags[fdef->flagcount].type = type;
  599 
  600     fdef->flagcount++;
  601     fdef->flags = realloc(fdef->flags, sizeof(paramflag) * (fdef->flagcount + 1));
  602 }
  603 
  604 // FREEFUNCDEF()
  605 //
  606 // Frees the function definition members
  607 //
  608 // Parameters:
  609 //   pointer to function definition
  610 //
  611 // Return value:
  612 //   none
  613 static void freefuncdef(funcdef *fdef) {
  614     unsigned long   i;
  615     
  616     for (i=0; i<fdef->outcount; i++) {
  617         free(fdef->outputs[i].content);
  618     }
  619     for (i=0; i<fdef->flagcount; i++) {
  620         free(fdef->flags[i].flag);
  621     }
  622     
  623     free(fdef->fbase);
  624     
  625     free(fdef->flags);
  626     free(fdef->outputs);
  627 }
  628 
  629 // MATCHFUNCDEF()
  630 //
  631 // Matches needle against function definition
  632 //
  633 // Parameters:
  634 //   pointer to function definition
  635 //   needle
  636 //   number of functions in fdefs array
  637 //
  638 // Return value:
  639 //   -1 if no match
  640 //   index of function matching otherwise
  641 static int matchfuncdef(funcdef *fdefs, char *needle, unsigned long count) {
  642     unsigned long   i;
  643     for (i=0; i<count; i++) {
  644         if (!strcmp(needle, fdefs[i].fbase)) {
  645             return i;
  646         }
  647     }
  648     return -1;
  649 }
  650 
  651 // GETFUNCDATA()
  652 //
  653 // Dumps the content of n-th data member of a particular type in the function
  654 // definition
  655 //
  656 // Parameters:
  657 //   pointer to function definition
  658 //   needle
  659 //   number of functions in fdefs array
  660 //
  661 // Return value:
  662 //   -1 if no match
  663 //   index of function matching otherwise
  664 static char *getfuncdata(funcdef *fdef, unsigned long count, int type) {
  665     unsigned long   i, j;
  666     char        *reval;
  667     
  668     for (i=0, j=0; i<fdef->outcount; i++) {
  669         if (fdef->outputs[i].id == type) { 
  670             if (j++ == count) {
  671                 reval = strdup(fdef->outputs[i].content);
  672                 return reval;
  673             }
  674         }
  675     }
  676     return NULL;
  677 }
  678 
  679 // CLEARFUNCDATA()
  680 //
  681 // Frees and clears the data in the function definition, not the function
  682 // definition itself.
  683 //
  684 // Parameters:
  685 //   pointer to function definition
  686 //
  687 // Return value:
  688 //   none
  689 static void clearfuncdata(funcdef *fdef) {
  690     unsigned long   i;
  691     
  692     for (i=0; i<fdef->outcount; i++) {
  693         free(fdef->outputs[i].content);
  694     }
  695     fdef->outcount = 0;
  696     fdef->outputs = realloc(fdef->outputs, sizeof(outformat));
  697 }
  698 
  699 // ADDSHELLBUILTIN()
  700 //
  701 // Adds another shell builtin that doesn't take a parameter, which are handled
  702 // with extra care.
  703 //
  704 // Parameters:
  705 //   pointer to shell builtins array
  706 //   name of the builtin
  707 //
  708 // Return value:
  709 //   none
  710 static void addshellbuiltin(shellbuiltins *shbin, char *name) {
  711     shbin->names[shbin->count] = strdup(name);
  712     shbin->count++;
  713     shbin->names = realloc(shbin->names, (sizeof(char*)) * (shbin->count + 1));
  714 }
  715 
  716 // FREESHELLBUILTINS()
  717 //
  718 // Frees the shell builtins members
  719 //
  720 // Parameters:
  721 //   pointer to shell builtins
  722 //
  723 // Return value:
  724 //   none
  725 static void freeshellbuiltins(shellbuiltins *shbin) {
  726     unsigned long   i;
  727     
  728     for (i=0; i<shbin->count; i++) {
  729         free(shbin->names[i]);
  730     }
  731     free(shbin->names);
  732 }
  733 
  734 // ISSHELLBUILTIN()
  735 //
  736 // Checks if the name is a known shell builtin or no
  737 //
  738 // Parameters:
  739 //   pointer to shell builtins
  740 //   needle
  741 //
  742 // Return value:
  743 //   0 if not matched
  744 //   1 if matched
  745 static int isshellbuiltin(shellbuiltins *shbin, char *name) {
  746     unsigned long   i;
  747     
  748     for (i=0; i<shbin->count; i++) {
  749         if (!strcmp(name, shbin->names[i])) { return 1; }
  750     }
  751     return 0;
  752 }
  753 
  754 // PARSEDOINST()
  755 //
  756 // Parses the doinst.sh script. This is the complex one, black magic, weird
  757 // code, hopes and prayers.
  758 //
  759 // Parameters:
  760 //   the parsed doinst.sh
  761 //   destination directory (viz pdef.destdir)
  762 //   pointer to package info where we write data
  763 //   id of action, whether we are installing or just getting package info
  764 //
  765 // Return value:
  766 //   0, always
  767 static int parsedoinst(char *line, char *ddir, pkginfo *pinfo, int action, off_t linelen) {
  768     char        *ptr, *rptr, *eptr, *fptr, *tmp, *tmp2, *tmp3, *tmp4;
  769     funcdef     *fdef;
  770     unsigned long   handfuncount, i;
  771     shellbuiltins   shbin;
  772     
  773     int     reval;
  774     int     subdepth, subbottom;
  775     int     qstatus, pstatus, sstatus;
  776     // qstatus controls status of ` subshells
  777     // pstatus controls status of parsing, since
  778     // we want some stuff sequentional
  779     // status tells us if we are going strictly
  780     // for slackware-likes or no
  781     // this counts for ifs, fors and cases
  782     
  783     subshell    *shell;
  784     
  785     ///////////////////////////////////////////////
  786     // Here is definition of shell builtins that //
  787     // do not take any parameter at all.         //
  788     ///////////////////////////////////////////////
  789     shbin.count = 0;
  790     shbin.names = malloc(sizeof(char*));
  791     addshellbuiltin(&shbin, "then");
  792     addshellbuiltin(&shbin, "else");
  793     addshellbuiltin(&shbin, "do");
  794     addshellbuiltin(&shbin, ":");
  795     addshellbuiltin(&shbin, "&&");
  796     addshellbuiltin(&shbin, "||");
  797     ///////////////////////////////////////////////
  798     // End of the definition part                //
  799     ///////////////////////////////////////////////
  800     
  801     handfuncount = 4;
  802     fdef = malloc(sizeof(funcdef) * handfuncount);
  803     ///////////////////////////////////////////////
  804     // Here is definition of function LN and the //
  805     // parameters that interest us               //
  806     ///////////////////////////////////////////////
  807     fdef[0].fbase = strdup("ln");
  808     fdef[0].outcount = 0;
  809     fdef[0].outputs = malloc(sizeof(outformat));
  810     fdef[0].flagcount = 0;
  811     fdef[0].flags = malloc(sizeof(paramflag));
  812     
  813     addflag(&fdef[0], "-S", SPACEDATA, SHORTOPT);               //0
  814     addflag(&fdef[0], "--suffix=", EQUIDATA, LONGOPT);          //1
  815     addflag(&fdef[0], "--backup=", EQUIDATA, LONGOPT);          //2
  816     addflag(&fdef[0], "--backup", NODATA, LONGOPT);             //3
  817     addflag(&fdef[0], "-b", NODATA, SHORTOPT);                  //4
  818     addflag(&fdef[0], "-s", NODATA, SHORTOPT);                  //5
  819     addflag(&fdef[0], "-f", NODATA, SHORTOPT);                  //6
  820     addflag(&fdef[0], "--force", NODATA, LONGOPT);              //7
  821     addflag(&fdef[0], "--target-directory=", EQUIDATA, LONGOPT);    //8
  822     addflag(&fdef[0], "--verbose", NODATA, LONGOPT);                //9
  823     addflag(&fdef[0], "-v", NODATA, SHORTOPT);                  //10
  824     addflag(&fdef[0], "--help", NODATA, LONGOPT);                   //11
  825     addflag(&fdef[0], "--version", NODATA, LONGOPT);                //12
  826     addflag(&fdef[0], "--interactive", NODATA, LONGOPT);            //13
  827     addflag(&fdef[0], "--symbolic", NODATA, LONGOPT);               //14
  828     addflag(&fdef[0], "--no-dereference", NODATA, LONGOPT);     //15
  829     addflag(&fdef[0], "--directory", NODATA, LONGOPT);              //16
  830     addflag(&fdef[0], "-i", NODATA, SHORTOPT);                  //17
  831     addflag(&fdef[0], "-F", NODATA, SHORTOPT);                  //18
  832     addflag(&fdef[0], "-d", NODATA, SHORTOPT);                  //19
  833     ///////////////////////////////////////////////
  834     // End of the definition part                //
  835     ///////////////////////////////////////////////
  836     
  837     ///////////////////////////////////////////////
  838     // Here is definition of function CD and the //
  839     // parameters that interest us               //
  840     ///////////////////////////////////////////////
  841     fdef[1].fbase = strdup("cd");
  842     fdef[1].outcount = 0;
  843     fdef[1].outputs = malloc(sizeof(outformat));
  844     fdef[1].flagcount = 0;
  845     fdef[1].flags = malloc(sizeof(paramflag));
  846     
  847     addflag(&fdef[1], "-L", SPACEDATA, SHORTOPT);
  848     addflag(&fdef[1], "-P", SPACEDATA, SHORTOPT);
  849     ///////////////////////////////////////////////
  850     // End of the definition part                //
  851     ///////////////////////////////////////////////
  852     
  853     ///////////////////////////////////////////////
  854     // Here is definition of remove functinon    //
  855     ///////////////////////////////////////////////
  856     fdef[2].fbase = strdup("rm");
  857     fdef[2].outcount = 0;
  858     fdef[2].outputs = malloc(sizeof(outformat));
  859     fdef[2].flagcount = 0;
  860     fdef[2].flags = malloc(sizeof(paramflag));
  861     
  862     addflag(&fdef[2], "-d", NODATA, SHORTOPT);
  863     addflag(&fdef[2], "-f", NODATA, SHORTOPT);
  864     addflag(&fdef[2], "-i", NODATA, SHORTOPT);
  865     addflag(&fdef[2], "-r", NODATA, SHORTOPT);
  866     addflag(&fdef[2], "-R", NODATA, SHORTOPT);
  867     addflag(&fdef[2], "-v", NODATA, SHORTOPT);
  868     addflag(&fdef[2], "--directory", NODATA, LONGOPT);
  869     addflag(&fdef[2], "--force", NODATA, LONGOPT);
  870     addflag(&fdef[2], "--interactive", NODATA, LONGOPT);
  871     addflag(&fdef[2], "--no-preserve-root", NODATA, LONGOPT);
  872     addflag(&fdef[2], "--preserve-root", NODATA, LONGOPT);
  873     addflag(&fdef[2], "--verbose", NODATA, LONGOPT);
  874     addflag(&fdef[2], "--help", NODATA, LONGOPT);
  875     addflag(&fdef[2], "--version", NODATA, LONGOPT);
  876     ///////////////////////////////////////////////
  877     // End of the definition part                //
  878     ///////////////////////////////////////////////
  879     
  880     ///////////////////////////////////////////////
  881     // Here is definition of temp functinon,     //
  882     // this is a restplace for any function not  //
  883     // matching any previous one.                //
  884     ///////////////////////////////////////////////
  885     fdef[3].fbase = strdup("");
  886     fdef[3].outcount = 0;
  887     fdef[3].outputs = malloc(sizeof(outformat));
  888     fdef[3].flagcount = 0;
  889     fdef[3].flags = malloc(sizeof(paramflag));
  890     ///////////////////////////////////////////////
  891     // End of the definition part                //
  892     ///////////////////////////////////////////////
  893     
  894     subdepth = 0;
  895     subbottom = 0;
  896     qstatus = QNONE;
  897     pstatus = 0;
  898     sstatus = 0;
  899     shell = malloc(sizeof(subshell));
  900     switch (action) {
  901         case 0:
  902             shell[0].pwd = strdup("/");         // We are not going to absolutize yet.
  903             break;
  904         default:
  905             shell[0].pwd = strdup(ddir);
  906             break;
  907     }
  908     shell[0].status = SBLOCK;           // This is a hack which prevents segfaults if some code eventually breaks the handling;
  909     
  910     ptr = line;
  911     if (linelen == 0) {
  912         linelen = strlen(line);
  913     }
  914     eptr = line + linelen;
  915     
  916     ptr = line;
  917     
  918     while ((ptr < eptr) && (*ptr != '\0')) {
  919         switch (*ptr) {
  920             case '#':
  921                     while ((*ptr != '\n') && (*ptr != '\0') && (ptr < eptr)) {
  922                         ptr++;
  923                     }
  924                 break;
  925             case '\\':
  926                 ptr++;
  927                 break;
  928             
  929             case ' ':
  930             case ';':
  931             case '\t':
  932             case '\n':
  933                 if (sstatus == 2) { sstatus = 0; }
  934                 break;
  935             
  936             case '{':
  937             case '(':
  938                 //pstatus = 1;  // We check for ( cd /foo ; ln -sf foo bar ) or .. rm -rf foo )
  939                 switch (pstatus) {
  940                     case 0:
  941                     case 4:
  942                         pstatus++;
  943                         break;
  944                     default:
  945                         pstatus = 0;
  946                         break;
  947                 }
  948                 
  949                 subdepth++;
  950                 shell = realloc(shell, sizeof(subshell) * (subdepth+1));
  951                 shell[subdepth].pwd = strdup(shell[subdepth-1].pwd);
  952                 shell[subdepth].status = SCLEAR;
  953                 break;
  954             case ')':
  955             case '}':
  956                 if (shell[subdepth].status == SCLEAR) {
  957                     switch (pstatus) {
  958                         case 7:
  959                             pstatus = 0;
  960                             ///////////////////////
  961                             // Nasty tmp mess    //
  962                             ///////////////////////
  963                             tmp2 = getfuncdata(&fdef[2], 0, -1);
  964                             if (tmp2 != NULL) {                             
  965                                 tmp = getfuncdata(&fdef[0], 1, -1);
  966                                 if (tmp != NULL) {
  967                                     if (!strcmp(tmp2, tmp)) {
  968                                         // More or less slack way, how about if it is a -symbolic- link?
  969                                         if ((tmp3 = getfuncdata(&fdef[0], 0, 5)) != NULL) {
  970                                             free(tmp3);
  971                                             
  972                                             switch (action) {
  973                                                 case 0:
  974                                                     addfile(pinfo, absolutizestr(tmp2, shell[subdepth].pwd), F_IRRELEVANT);
  975                                                     break;
  976                                                 case 1:
  977                                                     tmp3 = getfuncdata(&fdef[0], 0, -1);
  978                                                     tmp4 = absolutizestr(tmp, shell[subdepth].pwd);
  979                                                     symlink(tmp3, tmp4);
  980                                                     free(tmp3);
  981                                                     free(tmp4);
  982                                                     break;
  983                                             }
  984                                         }
  985                                         else if ((tmp3 = getfuncdata(&fdef[0], 0, 14)) != NULL) {
  986                                             free(tmp3);
  987                                                 
  988                                             switch (action) {
  989                                                 case 0:
  990                                                     addfile(pinfo, absolutizestr(tmp2, shell[subdepth].pwd), F_IRRELEVANT);
  991                                                     break;
  992                                                 case 1:
  993                                                     tmp3 = getfuncdata(&fdef[0], 0, -1);
  994                                                     tmp4 = absolutizestr(tmp, shell[subdepth].pwd);
  995                                                     symlink(tmp3, tmp4);
  996                                                     free(tmp3);
  997                                                     free(tmp4);
  998                                                     break;
  999                                             }
 1000                                         }
 1001                                         free(tmp);
 1002                                     } else {
 1003                                         free(tmp);
 1004                                     }
 1005                                     
 1006                                     free(tmp2);
 1007                                 } else {
 1008                                     free(tmp2);
 1009                                 }
 1010                             }
 1011                             break;
 1012                         case 3:
 1013                             pstatus ++;
 1014                             break;
 1015                         default:
 1016                             pstatus = 0;
 1017                         break;
 1018                     }
 1019 
 1020                     free(shell[subdepth].pwd);
 1021                     subdepth--;
 1022                     shell = realloc(shell, sizeof(subshell) * (subdepth+1));
 1023                 }
 1024                 break;
 1025             case '`':
 1026                 switch (qstatus) {
 1027                     case QNONE: 
 1028                         qstatus = QSUBSHELL;
 1029                         subdepth++;
 1030                         shell = realloc(shell, sizeof(subshell) * (subdepth+1));
 1031                         shell[subdepth].pwd = strdup(shell[subdepth-1].pwd);
 1032                         break;
 1033                     case QSUBSHELL:
 1034                         qstatus = QNONE;
 1035                         free(shell[subdepth].pwd);
 1036                         subdepth--;
 1037                         shell = realloc(shell, sizeof(subshell) * (subdepth+1));
 1038                         break;
 1039                 }
 1040                 break;
 1041             
 1042             default:
 1043                 rptr = ptr;
 1044                 
 1045                 while ((!isspace(*rptr)) && (*rptr != ';') && (*rptr != '(') && (*rptr != ')') && (*rptr != '{') && (*rptr != '}') && (*rptr != '\0') && (rptr < eptr)) {
 1046                     rptr++;
 1047                 }
 1048                 
 1049                 fptr = rptr;
 1050                 tmp = strndup(ptr, rptr - ptr);
 1051                 
 1052                 reval = matchfuncdef(fdef, tmp, 3);
 1053                 if (reval == -1) { reval = 3; free(fdef[reval].fbase); fdef[reval].fbase=strdup(tmp); }
 1054                 clearfuncdata(&fdef[reval]);
 1055                 
 1056                 if (!isshellbuiltin(&shbin, tmp)) {
 1057                     parsecommand(ptr, eptr, &fptr, &fdef[reval]);
 1058                 }
 1059                 free(tmp);              
 1060 
 1061                 ptr = fptr;
 1062                 switch (reval) {
 1063                     case 0: // symlink
 1064                         tmp2 = getfuncdata(&fdef[reval], 0, -1);
 1065                         
 1066                         if (tmp != NULL) {
 1067                             tmp = getfuncdata(&fdef[reval], 1, -1);
 1068                             if ((tmp != NULL)&&(*tmp != '\0')) {
 1069                                 if (pstatus == 6) { 
 1070                                     pstatus++; 
 1071                                 } else { 
 1072                                     pstatus = 0; 
 1073                                     if (sstatus == 0) {
 1074                                         switch (action) {
 1075                                             case 0:
 1076                                                 addfile(pinfo, absolutizestr(tmp, shell[subdepth].pwd), F_IRRELEVANT);
 1077                                                 break;
 1078                                             case 1:
 1079                                                 tmp3 = absolutizestr(tmp, shell[subdepth].pwd);
 1080                                                 fprintf(stderr, "Installing %s -> %s\n", tmp3, tmp2);
 1081                                                 symlink(tmp2, tmp3);
 1082                                                 free(tmp3);
 1083                                         }
 1084                                     } // else protected and we don't do any other than what removepkg would see
 1085                                 }
 1086                                 free(tmp);
 1087                             } else {
 1088                                 pstatus = 0;
 1089                             }
 1090                             free(tmp2);
 1091                         } else {
 1092                             pstatus = 0;
 1093                         }
 1094                         break;
 1095                     case 1: // cd
 1096                         tmp = getfuncdata(&fdef[reval], 0, -1);
 1097                     
 1098                         if ((pstatus == 1) || (pstatus == 5)) { pstatus ++; }
 1099                         
 1100                         if (tmp != NULL) {
 1101                             if (tmp[0] == '/') {
 1102                                 free(shell[subdepth].pwd);
 1103                                 shell[subdepth].pwd = strdup(tmp);
 1104                             } else {
 1105                                 free(shell[subdepth].pwd);
 1106                                 shell[subdepth].pwd = absolutizestr(tmp, shell[subdepth-1].pwd);
 1107                             }
 1108                             free(tmp);
 1109                         }
 1110                         break;
 1111                     case 2: // rm
 1112                         tmp = getfuncdata(&fdef[reval], 0, -1);
 1113                         if (tmp != NULL) {
 1114                             if (pstatus == 2) { pstatus++; } else { pstatus = 0; }
 1115                             free(tmp);
 1116                         }
 1117                         break;
 1118                     default:                    
 1119                         pstatus = 0;
 1120                         if (!strcmp(fdef[reval].fbase, "case")) {
 1121                             shell[subdepth].status = SBLOCK;
 1122                             sstatus = 1;
 1123                         }
 1124                         if (!strcmp(fdef[reval].fbase, "esac")) {
 1125                             shell[subdepth].status = SCLEAR;
 1126                             sstatus = 0;
 1127                         }
 1128                         if ((!strcmp(fdef[reval].fbase, "&&")) || (!strcmp(fdef[reval].fbase, "||"))) {
 1129                             sstatus = 2;
 1130                         }
 1131                         
 1132                         if ((!strcmp(fdef[reval].fbase, "if")) || (!strcmp(fdef[reval].fbase, "do"))) {
 1133                             sstatus = 1;
 1134                         }
 1135                         
 1136                         if ((!strcmp(fdef[reval].fbase, "fi")) || (!strcmp(fdef[reval].fbase, "done"))) {
 1137                             sstatus = 0;
 1138                         }
 1139                         break;
 1140                 }
 1141 
 1142                 if ((*ptr == '\0')  || (ptr == eptr)) {
 1143                     freeshellbuiltins(&shbin);
 1144                     free(shell[0].pwd);
 1145                     free(shell);
 1146                     for (i=0; i<handfuncount; i++) {
 1147                         freefuncdef(&fdef[i]);
 1148                     }
 1149                     free(fdef);
 1150                     return 0;
 1151                 }
 1152                 break;
 1153         }
 1154         ptr++;
 1155     }
 1156     
 1157     free(shell[0].pwd);
 1158     free(shell);
 1159     
 1160     freeshellbuiltins(&shbin);
 1161     
 1162     for (i=0; i<handfuncount; i++) {
 1163         freefuncdef(&fdef[i]);
 1164     }
 1165 
 1166     free(fdef);
 1167     
 1168     return 0;
 1169 }
 1170 #else
 1171 ///////////////////////////////////////////////////////////////////////////////
 1172 //                                                                           //
 1173 // T R I V I A L   S H E L L   S E M I P A R S I N G                         //
 1174 //                                                                           //
 1175 ///////////////////////////////////////////////////////////////////////////////
 1176 
 1177 
 1178 // FREELINKINFO()
 1179 //
 1180 // Frees information about a symlink
 1181 //
 1182 // Parameters:
 1183 //   pointer to linkinfo
 1184 //
 1185 // Return value:
 1186 //   none
 1187 static void freelinkinfo(linkinfo *tofree) {
 1188     if (tofree->linkfile != NULL) { free(tofree->linkfile); }
 1189     if (tofree->target != NULL) { free(tofree->target); }
 1190     free(tofree);
 1191 }
 1192 
 1193 // STRNCHR()
 1194 //
 1195 // Same as strchr, but never goes over len chars.
 1196 //
 1197 // Parameters:
 1198 //   string checked
 1199 //   needle character
 1200 //   size of buffer
 1201 //
 1202 // Return value:
 1203 //   pointer to first match of needle
 1204 //   NULL if not matched
 1205 static char *strnchr(char *s, int c, unsigned long len) {
 1206     char        *ptr;
 1207 
 1208     for (ptr = s; (char*)ptr < ((char*)s)+len; ptr++) {
 1209         if (*ptr == c) { return ptr; }
 1210     }
 1211     
 1212     return NULL;
 1213 }
 1214 
 1215 // CHECKFORCOMMENT()
 1216 //
 1217 // Checks if the given line contains comment.
 1218 //
 1219 // Parameters:
 1220 //   the line
 1221 //
 1222 // Return value:
 1223 //   0 if no comment
 1224 //   1 if comment
 1225 static int checkforcomment(char *line) {
 1226     char        *ptr;
 1227 
 1228     ptr = line;
 1229     while ((*ptr != '\n') && (*ptr != '\0')) {
 1230         if (*ptr == '#') {
 1231             *ptr = '\0';
 1232             return 1;
 1233         }
 1234         ptr++;
 1235     }
 1236     return 0;
 1237 }
 1238 
 1239 // READLINE()
 1240 //
 1241 // Reads a line from given source
 1242 //
 1243 // Parameters:
 1244 //   pointer to the line, it will be changed to sthe new line.
 1245 //   ending pointer
 1246 //
 1247 // Return value:
 1248 //   malloced line
 1249 static char *readline(char **ptr, char *eptr) {
 1250     char        *line, *hptr;
 1251 
 1252     do {
 1253         if ((hptr = strnchr(*ptr, '\n', eptr - *ptr)) == NULL) {
 1254             hptr = eptr;
 1255         }
 1256     } while (*(hptr-1) == '\\');
 1257     line = malloc(hptr - *ptr + 1);
 1258     strncpy(line, *ptr, hptr - *ptr);
 1259     line[hptr - *ptr] = '\0';
 1260     
 1261     *ptr = hptr + 1;
 1262     
 1263     return line;
 1264 }
 1265 
 1266 // LINETOLINK()
 1267 //
 1268 // Checks if the symlink is on the given line and if it is created slackware
 1269 // style. If so, it gives details about the symlink.
 1270 //
 1271 // Parameters:
 1272 //   line
 1273 //
 1274 // Return value:
 1275 //   pointer symlink information
 1276 //   NULL if not slackware symlink
 1277 static linkinfo *linetolink(char *line) {
 1278     char        *rptr, *rhptr, *tmp;        // these for reversing the script
 1279     linkinfo    *reval;
 1280     
 1281     reval = malloc(sizeof(linkinfo));
 1282     reval->linkfile = NULL;
 1283     reval->target = NULL;
 1284     
 1285     rptr = strstr(line, "( cd ");
 1286     if (rptr == NULL) { 
 1287         freelinkinfo(reval);
 1288         return NULL;
 1289     }
 1290 
 1291     rptr += 4;
 1292     *rptr = '/';    // We need a prefixing '/', and the previous data is of no interest
 1293     if ((rhptr = strstr(line, " ; ")) == NULL) { 
 1294         freelinkinfo(reval);
 1295         return NULL;
 1296     }
 1297     *rhptr = '\0';
 1298     
 1299     tmp = strdup(rptr);
 1300 
 1301     rhptr++;
 1302     if ((rptr = strstr(rhptr, "ln -sf")) == NULL) {
 1303         free(tmp);
 1304         freelinkinfo(reval);
 1305         return NULL;
 1306     }
 1307     
 1308     rptr += 7;
 1309 
 1310     if ((rhptr = strchr(rptr, ' ')) == NULL) {
 1311         free(tmp);
 1312         freelinkinfo(reval);
 1313         return NULL;
 1314     }
 1315     *rhptr = '\0';
 1316     
 1317     reval->target = strdup(rptr);
 1318 
 1319     rptr = rhptr+1;
 1320     
 1321     if ((rhptr = strchr(rptr, ' ')) == NULL) {
 1322         free(tmp);
 1323         freelinkinfo(reval);
 1324         return NULL;
 1325     }
 1326     *rhptr = '\0';
 1327 
 1328     if (*(rhptr+1) != ')') {
 1329         free(tmp);
 1330         freelinkinfo(reval);
 1331         return NULL;
 1332     }
 1333 
 1334     *rhptr = '\0';
 1335 
 1336     reval->linkfile = absolutizestr(rptr, tmp);
 1337     free(tmp);
 1338 
 1339     return reval;
 1340 }
 1341 
 1342 // LINETORM()
 1343 //
 1344 // Checks if the rm is on the given line and if it is created slackware
 1345 // style. If so, it gives details about the rm.
 1346 //
 1347 // Parameters:
 1348 //   line
 1349 //
 1350 // Return value:
 1351 //   file which would be removed
 1352 //   NULL if not slackware rm
 1353 static char *linetorm(char *line) {
 1354     char        *rptr, *rhptr, *reval, *tmp;        // these for reversing the script
 1355     
 1356     rptr = strstr(line, "( cd ");
 1357     if (rptr == NULL) {
 1358         return NULL;
 1359     }
 1360 
 1361     rptr += 4;
 1362     *rptr = '/';    // We need a prefixing '/', and the previous data is of no interest
 1363     if ((rhptr = strstr(line, " ; ")) == NULL) { 
 1364         return NULL;
 1365     }
 1366     *rhptr = '\0';
 1367     
 1368     tmp = strdup(rptr);
 1369 
 1370     rhptr++;
 1371     if ((rptr = strstr(rhptr, "rm -rf")) == NULL) {
 1372         free(tmp);
 1373         return NULL;
 1374     }
 1375     
 1376     rptr += 7;
 1377     
 1378     if ((rhptr = strrchr(rptr, ' ')) == NULL) {
 1379         free(tmp);
 1380         return NULL;
 1381     }
 1382     *rhptr = '\0';
 1383     
 1384     reval = absolutizestr(rptr, tmp);
 1385     free(tmp);
 1386 
 1387     if (*(rhptr+1) != ')') {
 1388         free(tmp);
 1389         free(reval);
 1390         return NULL;
 1391     }
 1392 
 1393     return reval;
 1394 }
 1395 
 1396 // PARSEDOINST()
 1397 //
 1398 // Parses the doinst.sh script. This is the trivial one, it only checks for
 1399 // those generated by the official slackware makepkg
 1400 //
 1401 // Parameters:
 1402 //   the parsed doinst.sh
 1403 //   destination directory (viz pdef.destdir)
 1404 //   pointer to package info where we write data
 1405 //   id of action, whether we are installing or just getting package info
 1406 //
 1407 // Return value:
 1408 //   0, always
 1409 static int parsedoinst(char *fullfile, char *dirprefix, pkginfo *pinfo, int action) {
 1410     char        *line, *oldline, *tmp, *tmpcomp, *processedline, *ptr;
 1411     linkinfo    *tstlink;
 1412     unsigned long   filesize;
 1413     
 1414     line = NULL;
 1415     filesize = strlen(fullfile);
 1416     
 1417     ptr = fullfile;
 1418     
 1419     do {
 1420         oldline = line;
 1421         line = readline(&ptr, fullfile + filesize);
 1422         checkforcomment(line);
 1423         if (*line != '\0') {
 1424             processedline=strdup(line); // We dup here instead of before checkforcomment, since we want comments lost anyway
 1425             if ((tstlink = linetolink(processedline)) != NULL) {
 1426                 if ((tmp = linetorm(oldline)) != NULL) {
 1427                     tmpcomp = absolutizestr(tmp, dirprefix);
 1428                     free(tmp);
 1429                     tmp = absolutizestr(tstlink->linkfile, dirprefix);
 1430                     
 1431                     if (!strcmp(tmp, tmpcomp)) {    // is the previous rm and the current ln the same?
 1432                         switch (action) {
 1433                             case 0:
 1434                                 pinfo->filecount++;
 1435                                 pinfo->files = realloc(pinfo->files, sizeof(char*) *  pinfo->filecount);
 1436                                 pinfo->files[pinfo->filecount-1] = strdup(tmp);
 1437                                 break;
 1438                             case 1:
 1439                                 symlink(tstlink->target, tmp);
 1440                                 break;
 1441                         }
 1442                     }
 1443                     
 1444                     free(tmpcomp);
 1445                     free(tmp);
 1446                 }
 1447                 freelinkinfo(tstlink);
 1448             }
 1449             free(processedline);
 1450         }
 1451         free(oldline);
 1452     } while((void*)ptr < (((void*)fullfile) + filesize));
 1453     free(line);
 1454     
 1455     return 0;
 1456 }
 1457 ///////////////////////////////////////////////////////////////////////////////
 1458 #endif
 1459 ///////////////////////////////////////////////////////////////////////////////
 1460 //                                                                           //
 1461 // S L A C K W A R E   P A R S I N G   F U N C T I O N S                     //
 1462 //                                                                           //
 1463 ///////////////////////////////////////////////////////////////////////////////
 1464 
 1465 // PARSESLACKNAME()
 1466 //
 1467 // Attempts to parse the package information from filename, expecting a given
 1468 // filename format.
 1469 //
 1470 // Parameters:
 1471 //   filename
 1472 //   pointer to package info, to which data is written
 1473 //
 1474 // Return value:
 1475 //   0 if no problem
 1476 //   1 if troubles parsing the filename
 1477 static int parseslackname(char *name, pkginfo *pinfo) {
 1478     char        *parsed, *ptr;
 1479     
 1480     parsed = strdup(name);
 1481     
 1482     // strip off .tgz
 1483     if ((ptr = strrchr(parsed, '.')) == NULL) {
 1484         free(parsed);
 1485         return 1;
 1486     }
 1487     *ptr = '\0';
 1488     
 1489     // strip off build
 1490     if ((ptr = strrchr(parsed, '-')) == NULL) {
 1491         free(parsed);
 1492         return 1;
 1493     }
 1494     *ptr = '\0';
 1495     
 1496     // strip off arch
 1497     if ((ptr = strrchr(parsed, '-')) == NULL) {
 1498         free(parsed);
 1499         return 1;
 1500     }
 1501     *ptr = '\0';
 1502     
 1503     // get version
 1504     if ((ptr = strrchr(parsed, '-')) == NULL) {
 1505         free(parsed);
 1506         return 1;
 1507     }
 1508     *ptr = '\0';
 1509     pinfo->version = strdup(ptr+1);
 1510     pinfo->name = strdup(parsed);
 1511     
 1512     free(parsed);
 1513     return 0;
 1514 }
 1515 
 1516 // PARSESLACKDESC()
 1517 //
 1518 // Parses slack-desc file. First fine line is taken as description, and if
 1519 // parsing the filename fails, the package name is obtained from the
 1520 // slack-desc as well (format packagename: description description).
 1521 //
 1522 // Parameters:
 1523 //   the whole slack-desc file
 1524 //   pointer package info, to which data is written
 1525 //
 1526 // Return value:
 1527 //   0, always
 1528 static int parseslackdesc(char *fullfile, pkginfo *pinfo) {
 1529     char        *ptr, *rptr;
 1530     
 1531     ptr = fullfile;
 1532     while ((isspace(*ptr)) || (*ptr == '#')  || (*ptr == '\0')) {
 1533         while ((*ptr != '\n') && (*ptr != '\0')) {
 1534             ptr++;
 1535         }
 1536         ptr++;
 1537     }
 1538     if ((rptr = strchr(ptr, ':')) != NULL) {
 1539         if (pinfo->name == NULL) {
 1540             *rptr = '\0';
 1541             pinfo->name = strdup(ptr);
 1542         }
 1543         ptr = rptr + 1;
 1544         while (isspace(*ptr)) {
 1545             ptr++;
 1546         }
 1547     }
 1548     rptr = ptr;
 1549     while ((*rptr != '\n') && (*rptr != '\0')) {
 1550         rptr++;
 1551     }
 1552     *rptr='\0';
 1553     pinfo->description = strdup(ptr);
 1554     return 0;
 1555 }
 1556 
 1557 // ENSUREDATA()
 1558 //
 1559 // Ensures there is some basic package information about the package, no matter
 1560 // what happens.
 1561 //
 1562 // Parameters:
 1563 //   the filename
 1564 //   pointer package info, to which data is written
 1565 //
 1566 // Return value:
 1567 //   void
 1568 static void ensuredata(char *fname, pkginfo *pinfo) {
 1569     char *eptr, *fptr;
 1570     
 1571     if (pinfo->name == NULL) {
 1572         eptr = fname + strlen(fname);
 1573         
 1574         fptr = fname;
 1575         while ((fptr < eptr)) {
 1576             if ((isdigit(*fptr)) && (fptr > fname)) {
 1577                 if (*(fptr-1) == '-') {
 1578                     fptr--;
 1579                     break;
 1580                 }
 1581             }
 1582             fptr++;
 1583         }
 1584         
 1585         pinfo->name = strndup(fname, fptr-fname);
 1586         if (pinfo->version == NULL) { 
 1587             pinfo->version = strdup(fptr+1);
 1588         }
 1589     }
 1590     
 1591     if (pinfo->version == NULL) { pinfo->version = strdup("unknown"); }
 1592     if (pinfo->description == NULL) { pinfo->description = strdup("Slackware package, no description."); }
 1593 }
 1594 
 1595 ///////////////////////////////////////////////////////////////////////////////
 1596 //                                                                           //
 1597 // A P I   F U N C T I O N S                                                 //
 1598 //                                                                           //
 1599 ///////////////////////////////////////////////////////////////////////////////
 1600 int identify(packdef pdef) {
 1601     struct stat     statbuf;
 1602     c_compdata      cstream;
 1603     comarchive      *tar_archive;
 1604     void            *filemap;
 1605     char            *obuf;
 1606     unsigned long   obuflen;
 1607     int             err;
 1608     
 1609     fstat(fileno(pdef.filepointer), &statbuf);
 1610     filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fileno(pdef.filepointer), 0);
 1611     
 1612     obuflen = 512;
 1613     obuf = malloc(obuflen);
 1614     
 1615     if (decompression_setup(&cstream, filemap, 0, statbuf.st_size, obuf, obuflen, C_GZIP)) {
 1616         decompression_cleanup(&cstream);
 1617         free(obuf);
 1618         munmap(filemap, statbuf.st_size);
 1619         return 0;
 1620     }
 1621     
 1622     if (decompression_init(&cstream) != CE_OK) {
 1623         decompression_cleanup(&cstream);
 1624         free(obuf);
 1625         munmap(filemap, statbuf.st_size);
 1626         return 0;
 1627     }
 1628     
 1629     tar_archive = init_archive(AT_TAR);
 1630     do {
 1631         if (tar_archive->stage == AS_NEWFILE) {
 1632             if (tar_archive->ftype == AF_DIRECTORY) {
 1633                 if ((!strcmp(tar_archive->name, "install/")) || (!strcmp(tar_archive->name, "./install/")) || (!strcmp(tar_archive->name, "install")) || (!strcmp(tar_archive->name, "./install"))) {
 1634                     decompression_cleanup(&cstream);
 1635                     free(obuf);
 1636                     munmap(filemap, statbuf.st_size);
 1637                     deinit_archive(tar_archive);
 1638                     return 0;
 1639                 }
 1640             }
 1641         }
 1642         
 1643         update_nextblock(tar_archive);
 1644         if (tar_archive->nextblock > obuflen) {
 1645             obuflen = tar_archive->nextblock;
 1646             obuf = realloc(obuf, obuflen);
 1647         }
 1648         
 1649         if (decompression_decompress(&cstream, tar_archive->nextblock, obuf) != CE_OK)
 1650             break;
 1651         
 1652         if (decompression_ammount_not_processed(&cstream) > 0)
 1653             break;
 1654         
 1655         update_stage(tar_archive);
 1656         
 1657         switch (tar_archive->stage) {
 1658             case AS_DATA:
 1659                 update_upfilesize(tar_archive);
 1660                 // Perform data handling when actually unpacking stuff
 1661                 break;
 1662             case AS_HEADER:
 1663                 clear_archive_member(tar_archive);
 1664                 break;
 1665         }
 1666         
 1667         err = parse_block(tar_archive, obuf);
 1668         
 1669         if (err)
 1670             break;
 1671     } while (decompression_ammount_left(&cstream, 0) > 0);
 1672     deinit_archive(tar_archive);
 1673     
 1674     decompression_cleanup(&cstream);
 1675     free(obuf);
 1676     munmap(filemap, statbuf.st_size);
 1677     return 1;
 1678 }
 1679 
 1680 int pkgdetails(packdef pdef, pkginfo *pinfo) {
 1681     struct stat statbuf;
 1682     char        *fullfile, *obuf;
 1683     unsigned long   obuflen;
 1684     off_t   fsize;
 1685     c_compdata  cstream;
 1686     void        *filemap;
 1687     comarchive  *tar_archive;
 1688     int     err;
 1689     
 1690     fstat(fileno(pdef.filepointer), &statbuf);
 1691     fsize = statbuf.st_size;    
 1692     filemap = mmap(0, fsize, PROT_READ, MAP_SHARED, fileno(pdef.filepointer), 0);
 1693     
 1694     obuflen = 512;
 1695     obuf = malloc(obuflen);
 1696     
 1697     parseslackname(basename(pdef.filename), pinfo);
 1698     err = decompression_setup(&cstream, filemap, 0, statbuf.st_size, obuf, obuflen, C_GZIP);
 1699     
 1700     if ((decompression_init(&cstream) != CE_OK) || (err != CE_OK)) {
 1701         decompression_cleanup(&cstream);
 1702         free(obuf);
 1703         munmap(filemap, fsize);
 1704         return 1;
 1705     }
 1706     
 1707     fullfile = NULL;
 1708     
 1709     tar_archive = init_archive(AT_TAR);
 1710     do {
 1711         if (tar_archive->stage == AS_NEWFILE) {
 1712             if ((strncmp(tar_archive->name, "./install/", 10)) && (strncmp(tar_archive->name, "install/", 8))) {
 1713                 addfile(pinfo, absolutizestr(tar_archive->name, "/"), (tar_archive->ftype == AF_DIRECTORY) ? F_DIRECTORY : F_REGULAR);
 1714                 pinfo->pkgsize += tar_archive->filesize;
 1715             } else  {
 1716                 if (switch_control_names(tar_archive->name) != -1) {
 1717                     fullfile = malloc(tar_archive->filesize);
 1718                 }
 1719             }
 1720         }
 1721         
 1722         update_nextblock(tar_archive);
 1723         if (tar_archive->nextblock > obuflen) {
 1724             obuflen = tar_archive->nextblock;
 1725             obuf = realloc(obuf, obuflen);
 1726         }
 1727         
 1728         if (decompression_decompress(&cstream, tar_archive->nextblock, obuf) != CE_OK)
 1729             break;
 1730         
 1731         if (decompression_ammount_not_processed(&cstream) > 0)
 1732             break;
 1733         
 1734         update_stage(tar_archive);
 1735         
 1736         switch (tar_archive->stage) {
 1737             case AS_DATA:
 1738                 if (fullfile != NULL) {
 1739                     memcpy(fullfile + tar_archive->upfilesize, obuf, ((tar_archive->filesize - tar_archive->upfilesize) > tar_archive->nextblock) ? tar_archive->nextblock : tar_archive->filesize - tar_archive->upfilesize);
 1740                 }
 1741                 
 1742                 update_upfilesize(tar_archive);
 1743                 break;
 1744             case AS_HEADER:
 1745                 if (fullfile != NULL) {
 1746                     switch (switch_control_names(tar_archive->name)) {
 1747                         case 0:
 1748                             if (pinfo->postinst.data == NULL) {
 1749                                 pinfo->postinst.len = tar_archive->filesize;
 1750                                 pinfo->postinst.data = malloc(pinfo->postinst.len);
 1751                                 memcpy(pinfo->postinst.data, fullfile, pinfo->postinst.len);
 1752                             }
 1753                             parsedoinst(fullfile, pdef.destdir, pinfo, 0, pinfo->postinst.len);
 1754                             break;
 1755                         case 1:
 1756                             parseslackdesc(fullfile, pinfo);
 1757                             break;
 1758                     }
 1759                     
 1760                     free(fullfile);
 1761                     fullfile = NULL;
 1762                 }
 1763                 
 1764                 clear_archive_member(tar_archive);
 1765                 break;
 1766         }
 1767         
 1768         err = parse_block(tar_archive, obuf);
 1769         
 1770         if (err)
 1771             break;
 1772     } while (decompression_ammount_left(&cstream, 0) > 0);
 1773     deinit_archive(tar_archive);
 1774     decompression_cleanup(&cstream);
 1775     free(obuf);
 1776     munmap(filemap, fsize);
 1777     
 1778     ensuredata(pdef.filename, pinfo);
 1779 
 1780     if (pinfo->postinst.data != NULL) {
 1781         // Installpkg passes this. Although no script really uses
 1782         // it, let's be nice.
 1783         pinfo->postinst.parameters[A_IRRELEVANT] = strdup("-install");
 1784     }
 1785 
 1786     return 0;
 1787 }
 1788 
 1789 int pkginstall(packdef pdef) {
 1790     FILE        *fpout;
 1791     struct stat statbuf;
 1792     char        *fullfile, *obuf, *curpath;
 1793     unsigned long   obuflen;
 1794     off_t           fsize;
 1795     c_compdata  cstream;
 1796     comarchive  *tar_archive;
 1797     void        *filemap;
 1798     int     err;
 1799     
 1800     fstat(fileno(pdef.filepointer), &statbuf);
 1801     fsize = statbuf.st_size;    
 1802     filemap = mmap(0, fsize, PROT_READ, MAP_SHARED, fileno(pdef.filepointer), 0);
 1803     
 1804     obuflen = 512;
 1805     obuf = malloc(obuflen);
 1806     
 1807     curpath = NULL;
 1808     fullfile = NULL;
 1809     fpout = NULL;
 1810     err = decompression_setup(&cstream, filemap, 0, statbuf.st_size, obuf, obuflen, C_GZIP);
 1811     
 1812     if ((decompression_init(&cstream) != CE_OK) || (err != CE_OK)) {
 1813         decompression_cleanup(&cstream);
 1814         free(obuf);
 1815         munmap(filemap, fsize);
 1816         return 1;
 1817     }
 1818     
 1819     tar_archive = init_archive(AT_TAR);
 1820     do {
 1821         if (tar_archive->stage == AS_NEWFILE) {
 1822             free(curpath);
 1823             curpath = NULL;
 1824             
 1825             if ((strncmp(tar_archive->name, "./install/", 10)) && (strncmp(tar_archive->name, "install/", 8))) {
 1826                 curpath = absolutizestr(tar_archive->name, pdef.destdir);
 1827                 // Create relevant files
 1828                 switch (tar_archive->ftype) {
 1829                     case AF_REGULAR:
 1830                             if (fpout != NULL) { 
 1831                                 fclose(fpout);
 1832                             }
 1833                             if ((fpout = fopen(curpath, "w")) == NULL) {
 1834                                 free(curpath);
 1835                                 free(obuf);
 1836                                 decompression_cleanup(&cstream);
 1837                                 munmap(filemap, fsize);
 1838                                 deinit_archive(tar_archive);
 1839                                 return 2;
 1840                             }
 1841                             
 1842                             FCHOWNMOD(fileno(fpout), tar_archive->mode, tar_archive->uid, tar_archive->gid);
 1843                             
 1844                             if (tar_archive->filesize == 0) {
 1845                                 // Nothing to write. We just created it.
 1846                                 fclose(fpout);
 1847                                 fpout = NULL;
 1848                                 
 1849                                 // For SUID and SGID; fchown + file open for writing + suid/sgid = suid/sgid may be ignored
 1850                                 CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid);
 1851                             }
 1852                         break;
 1853                     case AF_SYMLINK:
 1854                             symlink(tar_archive->linktarget, curpath);
 1855                             CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid);
 1856                         break;
 1857                     case AF_DEVNODE:
 1858                             mknod(curpath, tar_archive->mode, makedev(tar_archive->dmajor, tar_archive->dminor));
 1859                             CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid);
 1860                         break;
 1861                     case AF_FIFOBUF:
 1862                             mkfifo(curpath, tar_archive->mode);
 1863                             CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid);
 1864                         break;
 1865                     case AF_DIRECTORY:
 1866                             if (stat(curpath, &statbuf)) {
 1867                                 mkdir(curpath, tar_archive->mode);
 1868                                 CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid);
 1869                             }
 1870                         break;
 1871                 }
 1872             } else if ((switch_control_names(tar_archive->name) == 0) && (tar_archive->filesize>0)) {
 1873                 // We need the doinst.sh
 1874                 fullfile = malloc(tar_archive->filesize);
 1875             }
 1876         }
 1877         
 1878         update_nextblock(tar_archive);
 1879         if (tar_archive->nextblock > obuflen) {
 1880             obuflen = tar_archive->nextblock;
 1881             obuf = realloc(obuf, obuflen);
 1882         }
 1883         
 1884         if (decompression_decompress(&cstream, tar_archive->nextblock, obuf) != CE_OK)
 1885             break;
 1886         
 1887         if (decompression_ammount_not_processed(&cstream) > 0)
 1888             break;
 1889         
 1890         update_stage(tar_archive);
 1891         
 1892         switch (tar_archive->stage) {
 1893             case AS_DATA:
 1894                 // Feed data...
 1895                 if (tar_archive->ftype == AF_REGULAR) {
 1896                     if (fpout != NULL) {
 1897                         fwrite(obuf, ((tar_archive->filesize - tar_archive->upfilesize) > tar_archive->nextblock) ? tar_archive->nextblock : tar_archive->filesize - tar_archive->upfilesize, 1, fpout);
 1898                     }
 1899                 }
 1900                 
 1901                 if (fullfile != NULL) {
 1902                     memcpy(fullfile + tar_archive->upfilesize, obuf, ((tar_archive->filesize - tar_archive->upfilesize) > tar_archive->nextblock) ? tar_archive->nextblock : tar_archive->filesize - tar_archive->upfilesize);
 1903                 }
 1904                 
 1905                 update_upfilesize(tar_archive);
 1906                 break;
 1907             case AS_HEADER:
 1908                 // Clear up...
 1909                 if (tar_archive->ftype == AF_REGULAR) {
 1910                     if (fpout != NULL) {
 1911                         fsync(fileno(fpout));
 1912                         fclose(fpout);
 1913                         fpout = NULL;
 1914                         
 1915                         // For SUID and SGID; fchown + file open for writing + suid/sgid = suid/sgid may be ignored
 1916                         CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid);
 1917                     }
 1918                 }
 1919                 
 1920                 if (fullfile != NULL) {
 1921                     if (switch_control_names(tar_archive->name) == 0) {
 1922                         parsedoinst(fullfile, pdef.destdir, NULL, 1, tar_archive->filesize);
 1923                     }
 1924                     
 1925                     free(fullfile);
 1926                     fullfile = NULL;
 1927                 }
 1928                 
 1929                 clear_archive_member(tar_archive);
 1930                 break;
 1931         }
 1932         
 1933         err = parse_block(tar_archive, obuf);
 1934         
 1935         if (err)
 1936             break;
 1937     } while (decompression_ammount_left(&cstream, 0));
 1938     deinit_archive(tar_archive);
 1939     decompression_cleanup(&cstream);
 1940     free(obuf);
 1941     munmap(filemap, fsize);
 1942     
 1943     return 0;
 1944 }