| /* |
| * libdpkg - Debian packaging suite library routines |
| * trigdeferred.l - parsing of triggers/Deferred |
| * |
| * Copyright © 2007 Canonical Ltd |
| * written by Ian Jackson <ian@chiark.greenend.org.uk> |
| * |
| * This is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| %option prefix="trigdef_yy" |
| /* Reset the name to the default value (instead of using "trigdeferred.c") |
| * so that automake (ylwrap) can find it. */ |
| %option outfile="lex.yy.c" |
| %option noyywrap |
| %option batch |
| %option nodefault |
| %option perf-report |
| %option warn |
| %option nounput |
| |
| %x midline |
| |
| %{ |
| |
| #include <config.h> |
| #include <compat.h> |
| |
| #include <sys/stat.h> |
| #include <sys/fcntl.h> |
| |
| #include <dpkg/i18n.h> |
| #include <dpkg/dpkg.h> |
| #include <dpkg/dpkg-db.h> |
| #include <dpkg/file.h> |
| #include <dpkg/dir.h> |
| #include <dpkg/trigdeferred.h> |
| #include <dpkg/triglib.h> |
| |
| #define YY_NO_INPUT |
| #define YY_DECL int trigdef_parse(void) |
| |
| static struct varbuf fn, newfn; |
| |
| static const struct trigdefmeths *trigdef; |
| |
| %} |
| |
| %% |
| |
| [ \t\n] /* whitespace */ |
| #.*\n /* comments */ |
| [\x21-\x7e]+ { |
| trigdef->trig_begin(trigdef_yytext); |
| BEGIN(midline); |
| } |
| |
| <midline>[ \t] /* whitespace */ |
| <midline>[-0-9a-z][-+.0-9a-z]* { |
| if (trigdef_yytext[0] == '-' && trigdef_yytext[1]) |
| ohshit(_("invalid package name `%.250s' in triggers deferred " |
| "file `%.250s'"), trigdef_yytext, fn.buf); |
| trigdef->package(trigdef_yytext); |
| } |
| <midline>\n|#.*\n { |
| trigdef->trig_end(); |
| BEGIN(0); |
| } |
| <midline><<EOF>> { |
| ohshit(_("truncated triggers deferred file `%.250s'"), fn.buf); |
| } |
| |
| <*>. { |
| ohshit(_("syntax error in triggers deferred file `%.250s' at " |
| "character `%s'%s"), |
| fn.buf, yytext, YY_START == midline ? " midline": ""); |
| } |
| |
| %% |
| |
| /*---------- Deferred file handling ----------*/ |
| |
| static char *triggersdir; |
| static int lock_fd = -1; |
| static FILE *old_deferred; |
| static FILE *trig_new_deferred; |
| |
| static void |
| constructfn(struct varbuf *vb, const char *dir, const char *tail) |
| { |
| varbuf_reset(vb); |
| varbuf_add_str(vb, dir); |
| varbuf_add_char(vb, '/'); |
| varbuf_add_str(vb, tail); |
| varbuf_end_str(vb); |
| } |
| |
| /** |
| * Start processing of the triggers deferred file. |
| * |
| * @retval -1 Lock ENOENT with O_CREAT (directory does not exist). |
| * @retval -2 Unincorp empty, tduf_writeifempty unset. |
| * @retval -3 Unincorp ENOENT, tduf_writeifenoent unset. |
| * @retval 1 Unincorp ENOENT, tduf_writeifenoent set. |
| * @retval 2 Ok. |
| * |
| * For positive return values the caller must call trigdef_update_done! |
| */ |
| enum trigdef_update_status |
| trigdef_update_start(enum trigdef_updateflags uf) |
| { |
| struct stat stab; |
| int r; |
| |
| triggersdir = dpkg_db_get_path(TRIGGERSDIR); |
| |
| if (uf & tduf_write) { |
| constructfn(&fn, triggersdir, TRIGGERSLOCKFILE); |
| if (lock_fd == -1) { |
| lock_fd = open(fn.buf, O_RDWR | O_CREAT | O_TRUNC, 0600); |
| if (lock_fd == -1) { |
| if (!(errno == ENOENT && (uf & tduf_nolockok))) |
| ohshite(_("unable to open/create " |
| "triggers lockfile `%.250s'"), |
| fn.buf); |
| return tdus_error_no_dir; |
| } |
| } |
| |
| file_lock(&lock_fd, FILE_LOCK_WAIT, fn.buf, _("triggers area")); |
| } else { |
| /* Dummy for pop_cleanups. */ |
| push_cleanup(NULL, 0, NULL, 0, 0); |
| } |
| |
| constructfn(&fn, triggersdir, TRIGGERSDEFERREDFILE); |
| r = stat(fn.buf, &stab); |
| if (r) { |
| if (errno != ENOENT) |
| ohshite(_("unable to stat triggers deferred file `%.250s'"), |
| fn.buf); |
| } else if (!stab.st_size) { |
| if (!(uf & tduf_writeifempty)) { |
| pop_cleanup(ehflag_normaltidy); |
| return tdus_error_empty_deferred; |
| } |
| } |
| |
| if (old_deferred) |
| fclose(old_deferred); |
| old_deferred = fopen(fn.buf, "r"); |
| if (!old_deferred) { |
| if (errno != ENOENT) |
| ohshite(_("unable to open triggers deferred file `%.250s'"), |
| fn.buf); |
| if (!(uf & tduf_writeifenoent)) { |
| pop_cleanup(ehflag_normaltidy); |
| return tdus_error_no_deferred; |
| } |
| } |
| |
| if (uf & tduf_write) { |
| constructfn(&newfn, triggersdir, TRIGGERSDEFERREDFILE ".new"); |
| if (trig_new_deferred) |
| fclose(trig_new_deferred); |
| trig_new_deferred = fopen(newfn.buf, "w"); |
| if (!trig_new_deferred) |
| ohshite(_("unable to open/create new triggers deferred file `%.250s'"), |
| newfn.buf); |
| } |
| |
| if (!old_deferred) |
| return tdus_no_deferred; |
| |
| trigdef_yyrestart(old_deferred); |
| BEGIN(0); |
| |
| return tdus_ok; |
| } |
| |
| void |
| trigdef_set_methods(const struct trigdefmeths *methods) |
| { |
| trigdef = methods; |
| } |
| |
| void |
| trigdef_update_printf(const char *format, ...) |
| { |
| va_list ap; |
| |
| va_start(ap, format); |
| vfprintf(trig_new_deferred, format, ap); |
| va_end(ap); |
| } |
| |
| void |
| trigdef_process_done(void) |
| { |
| int r; |
| |
| if (old_deferred) { |
| if (ferror(old_deferred)) |
| ohshite(_("error reading triggers deferred file `%.250s'"), |
| fn.buf); |
| fclose(old_deferred); |
| old_deferred = NULL; |
| } |
| |
| if (trig_new_deferred) { |
| if (ferror(trig_new_deferred)) |
| ohshite(_("unable to write new triggers deferred " |
| "file `%.250s'"), newfn.buf); |
| r = fclose(trig_new_deferred); |
| trig_new_deferred = NULL; |
| if (r) |
| ohshite(_("unable to close new triggers deferred " |
| "file `%.250s'"), newfn.buf); |
| |
| if (rename(newfn.buf, fn.buf)) |
| ohshite(_("unable to install new triggers deferred " |
| "file `%.250s'"), fn.buf); |
| |
| dir_sync_path(triggersdir); |
| } |
| |
| free(triggersdir); |
| triggersdir = NULL; |
| |
| /* Unlock. */ |
| pop_cleanup(ehflag_normaltidy); |
| } |