"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 }