]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/ar/acpyacc.y
amd64: use register macros for gdb_cpu_getreg()
[FreeBSD/FreeBSD.git] / usr.bin / ar / acpyacc.y
1 %{
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4  *
5  * Copyright (c) 2008 Kai Wang
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/mman.h>
34 #include <sys/param.h>
35 #include <sys/queue.h>
36 #include <sys/stat.h>
37 #include <archive.h>
38 #include <archive_entry.h>
39 #include <dirent.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sysexits.h>
46 #include <unistd.h>
47
48 #include "ar.h"
49
50 #define TEMPLATE "arscp.XXXXXXXX"
51
52 struct list {
53         char            *str;
54         struct list     *next;
55 };
56
57
58 extern int      yylex(void);
59
60 static void     yyerror(const char *);
61 static void     arscp_addlib(char *archive, struct list *list);
62 static void     arscp_addmod(struct list *list);
63 static void     arscp_clear(void);
64 static int      arscp_copy(int ifd, int ofd);
65 static void     arscp_create(char *in, char *out);
66 static void     arscp_delete(struct list *list);
67 static void     arscp_dir(char *archive, struct list *list, char *rlt);
68 static void     arscp_end(int eval);
69 static void     arscp_extract(struct list *list);
70 static void     arscp_free_argv(void);
71 static void     arscp_free_mlist(struct list *list);
72 static void     arscp_list(void);
73 static struct list *arscp_mlist(struct list *list, char *str);
74 static void     arscp_mlist2argv(struct list *list);
75 static int      arscp_mlist_len(struct list *list);
76 static void     arscp_open(char *fname);
77 static void     arscp_prompt(void);
78 static void     arscp_replace(struct list *list);
79 static void     arscp_save(void);
80 static int      arscp_target_exist(void);
81
82 extern int               lineno;
83
84 static struct bsdar     *bsdar;
85 static char             *target;
86 static char             *tmpac;
87 static int               interactive;
88 static int               verbose;
89
90 %}
91
92 %token ADDLIB
93 %token ADDMOD
94 %token CLEAR
95 %token CREATE
96 %token DELETE
97 %token DIRECTORY
98 %token END
99 %token EXTRACT
100 %token LIST
101 %token OPEN
102 %token REPLACE
103 %token VERBOSE
104 %token SAVE
105 %token LP
106 %token RP
107 %token COMMA
108 %token EOL
109 %token <str> FNAME
110 %type <list> mod_list
111
112 %union {
113         char            *str;
114         struct list     *list;
115 }
116
117 %%
118
119 begin
120         : { arscp_prompt(); } ar_script
121         ;
122
123 ar_script
124         : cmd_list
125         |
126         ;
127
128 mod_list
129         : FNAME { $$ = arscp_mlist(NULL, $1); }
130         | mod_list separator FNAME { $$ = arscp_mlist($1, $3); }
131         ;
132
133 separator
134         : COMMA
135         |
136         ;
137
138 cmd_list
139         : rawcmd
140         | cmd_list rawcmd
141         ;
142
143 rawcmd
144         : cmd EOL { arscp_prompt(); }
145         ;
146
147 cmd
148         : addlib_cmd
149         | addmod_cmd
150         | clear_cmd
151         | create_cmd
152         | delete_cmd
153         | directory_cmd
154         | end_cmd
155         | extract_cmd
156         | list_cmd
157         | open_cmd
158         | replace_cmd
159         | verbose_cmd
160         | save_cmd
161         | invalid_cmd
162         | empty_cmd
163         | error
164         ;
165
166 addlib_cmd
167         : ADDLIB FNAME LP mod_list RP { arscp_addlib($2, $4); }
168         | ADDLIB FNAME { arscp_addlib($2, NULL); }
169         ;
170
171 addmod_cmd
172         : ADDMOD mod_list { arscp_addmod($2); }
173         ;
174
175 clear_cmd
176         : CLEAR { arscp_clear(); }
177         ;
178
179 create_cmd
180         : CREATE FNAME { arscp_create(NULL, $2); }
181         ;
182
183 delete_cmd
184         : DELETE mod_list { arscp_delete($2); }
185         ;
186
187 directory_cmd
188         : DIRECTORY FNAME { arscp_dir($2, NULL, NULL); }
189         | DIRECTORY FNAME LP mod_list RP { arscp_dir($2, $4, NULL); }
190         | DIRECTORY FNAME LP mod_list RP FNAME { arscp_dir($2, $4, $6); }
191         ;
192
193 end_cmd
194         : END { arscp_end(EX_OK); }
195         ;
196
197 extract_cmd
198         : EXTRACT mod_list { arscp_extract($2); }
199         ;
200
201 list_cmd
202         : LIST { arscp_list(); }
203         ;
204
205 open_cmd
206         : OPEN FNAME { arscp_open($2); }
207         ;
208
209 replace_cmd
210         : REPLACE mod_list { arscp_replace($2); }
211         ;
212
213 save_cmd
214         : SAVE { arscp_save(); }
215         ;
216
217 verbose_cmd
218         : VERBOSE { verbose = !verbose; }
219         ;
220
221 empty_cmd
222         :
223         ;
224
225 invalid_cmd
226         : FNAME { yyerror(NULL); }
227         ;
228
229 %%
230
231 /* ARGSUSED */
232 static void
233 yyerror(const char *s)
234 {
235
236         (void) s;
237         printf("Syntax error in archive script, line %d\n", lineno);
238 }
239
240 /*
241  * arscp_open first open an archive and check its validity. If the archive
242  * format is valid, it calls arscp_create to create a temporary copy of
243  * the archive.
244  */
245 static void
246 arscp_open(char *fname)
247 {
248         struct archive          *a;
249         struct archive_entry    *entry;
250         int                      r;
251
252         if ((a = archive_read_new()) == NULL)
253                 bsdar_errc(bsdar, EX_SOFTWARE, 0, "archive_read_new failed");
254         archive_read_support_format_ar(a);
255         AC(archive_read_open_filename(a, fname, DEF_BLKSZ));
256         if ((r = archive_read_next_header(a, &entry)))
257                 bsdar_warnc(bsdar, archive_errno(a), "%s",
258                     archive_error_string(a));
259         AC(archive_read_close(a));
260         AC(archive_read_free(a));
261         if (r != ARCHIVE_OK)
262                 return;
263         arscp_create(fname, fname);
264 }
265
266 /*
267  * Create archive. in != NULL indicate it's a OPEN cmd, and resulting
268  * archive is based on modification of an existing one. If in == NULL,
269  * we are in CREATE cmd and a new empty archive will be created.
270  */
271 static void
272 arscp_create(char *in, char *out)
273 {
274         struct archive          *a;
275         int                      ifd, ofd;
276
277         /* Delete previously created temporary archive, if any. */
278         if (tmpac) {
279                 if (unlink(tmpac) < 0)
280                         bsdar_errc(bsdar, EX_IOERR, errno, "unlink failed");
281                 free(tmpac);
282         }
283
284         tmpac = strdup(TEMPLATE);
285         if (tmpac == NULL)
286                 bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed");
287         if ((ofd = mkstemp(tmpac)) < 0)
288                 bsdar_errc(bsdar, EX_IOERR, errno, "mkstemp failed");
289
290         if (in) {
291                 /*
292                  * Command OPEN creates a temporary copy of the
293                  * input archive.
294                  */
295                 if ((ifd = open(in, O_RDONLY)) < 0) {
296                         bsdar_warnc(bsdar, errno, "open failed");
297                         return;
298                 }
299                 if (arscp_copy(ifd, ofd)) {
300                         bsdar_warnc(bsdar, 0, "arscp_copy failed");
301                         return;
302                 }
303                 close(ifd);
304                 close(ofd);
305         } else {
306                 /*
307                  * Command CREATE creates an "empty" archive.
308                  * (archive with only global header)
309                  */
310                 if ((a = archive_write_new()) == NULL)
311                         bsdar_errc(bsdar, EX_SOFTWARE, 0,
312                             "archive_write_new failed");
313                 archive_write_set_format_ar_svr4(a);
314                 AC(archive_write_open_fd(a, ofd));
315                 AC(archive_write_close(a));
316                 AC(archive_write_free(a));
317         }
318
319         /* Override previous target, if any. */
320         if (target)
321                 free(target);
322
323         target = out;
324         bsdar->filename = tmpac;
325 }
326
327 /* A file copying implementation using mmap. */
328 static int
329 arscp_copy(int ifd, int ofd)
330 {
331         struct stat              sb;
332         char                    *buf, *p;
333         ssize_t                  w;
334         size_t                   bytes;
335
336         if (fstat(ifd, &sb) < 0) {
337                 bsdar_warnc(bsdar, errno, "fstate failed");
338                 return (1);
339         }
340         if ((p = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, ifd,
341             (off_t)0)) == MAP_FAILED) {
342                 bsdar_warnc(bsdar, errno, "mmap failed");
343                 return (1);
344         }
345         for (buf = p, bytes = sb.st_size; bytes > 0; bytes -= w) {
346                 w = write(ofd, buf, bytes);
347                 if (w <= 0) {
348                         bsdar_warnc(bsdar, errno, "write failed");
349                         break;
350                 }
351         }
352         if (munmap(p, sb.st_size) < 0)
353                 bsdar_errc(bsdar, EX_SOFTWARE, errno, "munmap failed");
354         if (bytes > 0)
355                 return (1);
356
357         return (0);
358 }
359
360 /*
361  * Add all modules of archive to current archive, if list != NULL,
362  * only those modules specified in 'list' will be added.
363  */
364 static void
365 arscp_addlib(char *archive, struct list *list)
366 {
367
368         if (!arscp_target_exist())
369                 return;
370         arscp_mlist2argv(list);
371         bsdar->addlib = archive;
372         ar_mode_A(bsdar);
373         arscp_free_argv();
374         arscp_free_mlist(list);
375 }
376
377 /* Add modules into current archive. */
378 static void
379 arscp_addmod(struct list *list)
380 {
381
382         if (!arscp_target_exist())
383                 return;
384         arscp_mlist2argv(list);
385         ar_mode_q(bsdar);
386         arscp_free_argv();
387         arscp_free_mlist(list);
388 }
389
390 /* Delete modules from current archive. */
391 static void
392 arscp_delete(struct list *list)
393 {
394
395         if (!arscp_target_exist())
396                 return;
397         arscp_mlist2argv(list);
398         ar_mode_d(bsdar);
399         arscp_free_argv();
400         arscp_free_mlist(list);
401 }
402
403 /* Extract modules from current archive. */
404 static void
405 arscp_extract(struct list *list)
406 {
407
408         if (!arscp_target_exist())
409                 return;
410         arscp_mlist2argv(list);
411         ar_mode_x(bsdar);
412         arscp_free_argv();
413         arscp_free_mlist(list);
414 }
415
416 /* List modules of archive. (Simple Mode) */
417 static void
418 arscp_list(void)
419 {
420
421         if (!arscp_target_exist())
422                 return;
423         bsdar->argc = 0;
424         bsdar->argv = NULL;
425         /* Always verbose. */
426         bsdar->options |= AR_V;
427         ar_mode_t(bsdar);
428         bsdar->options &= ~AR_V;
429 }
430
431 /* List modules of archive. (Advance Mode) */
432 static void
433 arscp_dir(char *archive, struct list *list, char *rlt)
434 {
435         FILE    *out;
436
437         /* If rlt != NULL, redirect output to it */
438         out = NULL;
439         if (rlt) {
440                 out = stdout;
441                 if ((stdout = fopen(rlt, "w")) == NULL)
442                         bsdar_errc(bsdar, EX_IOERR, errno,
443                             "fopen %s failed", rlt);
444         }
445
446         bsdar->filename = archive;
447         if (list)
448                 arscp_mlist2argv(list);
449         else {
450                 bsdar->argc = 0;
451                 bsdar->argv = NULL;
452         }
453         if (verbose)
454                 bsdar->options |= AR_V;
455         ar_mode_t(bsdar);
456         bsdar->options &= ~AR_V;
457
458         if (rlt) {
459                 if (fclose(stdout) == EOF)
460                         bsdar_errc(bsdar, EX_IOERR, errno,
461                             "fclose %s failed", rlt);
462                 stdout = out;
463                 free(rlt);
464         }
465         free(archive);
466         bsdar->filename = tmpac;
467         arscp_free_argv();
468         arscp_free_mlist(list);
469 }
470
471
472 /* Replace modules of current archive. */
473 static void
474 arscp_replace(struct list *list)
475 {
476
477         if (!arscp_target_exist())
478                 return;
479         arscp_mlist2argv(list);
480         ar_mode_r(bsdar);
481         arscp_free_argv();
482         arscp_free_mlist(list);
483 }
484
485 /* Rename the temporary archive to the target archive. */
486 static void
487 arscp_save(void)
488 {
489         mode_t mask;
490
491         if (target) {
492                 if (rename(tmpac, target) < 0)
493                         bsdar_errc(bsdar, EX_IOERR, errno, "rename failed");
494                 /*
495                  * mkstemp creates temp files with mode 0600, here we
496                  * set target archive mode per process umask.
497                  */
498                 mask = umask(0);
499                 umask(mask);
500                 if (chmod(target, 0666 & ~mask) < 0)
501                         bsdar_errc(bsdar, EX_IOERR, errno, "chmod failed");
502                 free(tmpac);
503                 free(target);
504                 tmpac = NULL;
505                 target= NULL;
506                 bsdar->filename = NULL;
507         } else
508                 bsdar_warnc(bsdar, 0, "no open output archive");
509 }
510
511 /*
512  * Discard all the contents of current archive. This is achieved by
513  * invoking CREATE cmd on current archive.
514  */
515 static void
516 arscp_clear(void)
517 {
518         char            *new_target;
519
520         if (target) {
521                 new_target = strdup(target);
522                 if (new_target == NULL)
523                         bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed");
524                 arscp_create(NULL, new_target);
525         }
526 }
527
528 /*
529  * Quit ar(1). Note that END cmd will not SAVE current archive
530  * before exit.
531  */
532 static void
533 arscp_end(int eval)
534 {
535
536         if (target)
537                 free(target);
538         if (tmpac) {
539                 if (unlink(tmpac) == -1)
540                         bsdar_errc(bsdar, EX_IOERR, errno, "unlink %s failed",
541                             tmpac);
542                 free(tmpac);
543         }
544
545         exit(eval);
546 }
547
548 /*
549  * Check if target specified, i.e, whether OPEN or CREATE has been
550  * issued by user.
551  */
552 static int
553 arscp_target_exist(void)
554 {
555
556         if (target)
557                 return (1);
558
559         bsdar_warnc(bsdar, 0, "no open output archive");
560         return (0);
561 }
562
563 /* Construct module list. */
564 static struct list *
565 arscp_mlist(struct list *list, char *str)
566 {
567         struct list *l;
568
569         l = malloc(sizeof(*l));
570         if (l == NULL)
571                 bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed");
572         l->str = str;
573         l->next = list;
574
575         return (l);
576 }
577
578 /* Calculate the length of a mlist. */
579 static int
580 arscp_mlist_len(struct list *list)
581 {
582         int len;
583
584         for(len = 0; list; list = list->next)
585                 len++;
586
587         return (len);
588 }
589
590 /* Free the space allocated for mod_list. */
591 static void
592 arscp_free_mlist(struct list *list)
593 {
594         struct list *l;
595
596         /* Note that list->str was freed in arscp_free_argv. */
597         for(; list; list = l) {
598                 l = list->next;
599                 free(list);
600         }
601 }
602
603 /* Convert mlist to argv array. */
604 static void
605 arscp_mlist2argv(struct list *list)
606 {
607         char    **argv;
608         int       i, n;
609
610         n = arscp_mlist_len(list);
611         argv = malloc(n * sizeof(*argv));
612         if (argv == NULL)
613                 bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed");
614
615         /* Note that module names are stored in reverse order in mlist. */
616         for(i = n - 1; i >= 0; i--, list = list->next) {
617                 if (list == NULL)
618                         bsdar_errc(bsdar, EX_SOFTWARE, errno, "invalid mlist");
619                 argv[i] = list->str;
620         }
621
622         bsdar->argc = n;
623         bsdar->argv = argv;
624 }
625
626 /* Free space allocated for argv array and its elements. */
627 static void
628 arscp_free_argv(void)
629 {
630         int i;
631
632         for(i = 0; i < bsdar->argc; i++)
633                 free(bsdar->argv[i]);
634
635         free(bsdar->argv);
636 }
637
638 /* Show a prompt if we are in interactive mode */
639 static void
640 arscp_prompt(void)
641 {
642
643         if (interactive) {
644                 printf("AR >");
645                 fflush(stdout);
646         }
647 }
648
649 /* Main function for ar script mode. */
650 void
651 ar_mode_script(struct bsdar *ar)
652 {
653
654         bsdar = ar;
655         interactive = isatty(fileno(stdin));
656         while(yyparse()) {
657                 if (!interactive)
658                         arscp_end(1);
659         }
660
661         /* Script ends without END */
662         arscp_end(EX_OK);
663 }