| /* |
| * dselect - Debian package maintenance user interface |
| * method.cc - access method handling |
| * |
| * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk> |
| * Copyright © 2001,2002 Wichert Akkerman <wakkerma@debian.org> |
| * |
| * 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/>. |
| */ |
| |
| #include <config.h> |
| #include <compat.h> |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/file.h> |
| #include <sys/wait.h> |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <limits.h> |
| #include <ctype.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <dirent.h> |
| #include <signal.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| |
| #include <dpkg/i18n.h> |
| #include <dpkg/dpkg.h> |
| #include <dpkg/dpkg-db.h> |
| #include <dpkg/subproc.h> |
| #include <dpkg/command.h> |
| |
| #include "dselect.h" |
| #include "method.h" |
| |
| static const char *const methoddirectories[]= { |
| LIBDIR "/" METHODSDIR, |
| LOCALLIBDIR "/" METHODSDIR, |
| 0 |
| }; |
| |
| static char *methodlockfile= 0; |
| static int methlockfd= -1; |
| |
| static void |
| sthfailed(const char * reasoning) |
| { |
| char buf[2048]; |
| |
| curseson(); |
| clear(); |
| sprintf(buf,_("\n\n%s: %s\n"),DSELECT,reasoning); |
| addstr(buf); |
| attrset(A_BOLD); |
| addstr(_("\nPress <enter> to continue.")); |
| attrset(A_NORMAL); |
| refresh(); getch(); |
| } |
| |
| static void cu_unlockmethod(int, void**) { |
| struct flock fl; |
| |
| assert(methodlockfile); |
| assert(methlockfd); |
| fl.l_type=F_UNLCK; fl.l_whence= SEEK_SET; fl.l_start=fl.l_len=0; |
| if (fcntl(methlockfd,F_SETLK,&fl) == -1) |
| sthfailed("unable to unlock access method area"); |
| } |
| |
| static enum urqresult ensureoptions(void) { |
| const char *const *ccpp; |
| dselect_option *newoptions; |
| int nread; |
| |
| if (!options) { |
| newoptions= 0; |
| nread= 0; |
| for (ccpp= methoddirectories; *ccpp; ccpp++) |
| readmethods(*ccpp, &newoptions, &nread); |
| if (!newoptions) { |
| sthfailed("no access methods are available"); |
| return urqr_fail; |
| } |
| options= newoptions; |
| noptions= nread; |
| } |
| return urqr_normal; |
| } |
| |
| static enum urqresult lockmethod(void) { |
| struct flock fl; |
| |
| if (methodlockfile == NULL) |
| methodlockfile = dpkg_db_get_path(METHLOCKFILE); |
| |
| if (methlockfd == -1) { |
| methlockfd= open(methodlockfile, O_RDWR|O_CREAT|O_TRUNC, 0660); |
| if (methlockfd == -1) { |
| if ((errno == EPERM) || (errno == EACCES)) { |
| sthfailed("requested operation requires superuser privilege"); |
| return urqr_fail; |
| } |
| sthfailed("unable to open/create access method lockfile"); |
| return urqr_fail; |
| } |
| } |
| fl.l_type=F_WRLCK; fl.l_whence=SEEK_SET; fl.l_start=fl.l_len=0; |
| if (fcntl(methlockfd,F_SETLK,&fl) == -1) { |
| if (errno == EWOULDBLOCK || errno == EAGAIN) { |
| sthfailed("the access method area is already locked"); |
| return urqr_fail; |
| } |
| sthfailed("unable to lock access method area"); |
| return urqr_fail; |
| } |
| push_cleanup(cu_unlockmethod,~0, 0,0, 0); |
| return urqr_normal; |
| } |
| |
| static urqresult |
| falliblesubprocess(struct command *cmd) |
| { |
| pid_t pid; |
| int status, i, c; |
| |
| cursesoff(); |
| |
| subproc_signals_setup(cmd->name); |
| |
| pid = subproc_fork(); |
| if (pid == 0) { |
| subproc_signals_cleanup(0, 0); |
| command_exec(cmd); |
| } |
| |
| status = subproc_wait(pid, cmd->name); |
| |
| pop_cleanup(ehflag_normaltidy); |
| |
| fprintf(stderr, "\n"); |
| i = subproc_check(status, cmd->name, PROCWARN); |
| if (i == 0) { |
| sleep(1); |
| return urqr_normal; |
| } |
| fprintf(stderr,_("Press <enter> to continue.\n")); |
| m_output(stderr, _("<standard error>")); |
| do { c= fgetc(stdin); } while ((c == ERR && errno==EINTR) || ((c != '\n') && c != EOF)); |
| if ((c == ERR) || (c == EOF)) |
| ohshite(_("error reading acknowledgement of program failure message")); |
| return urqr_fail; |
| } |
| |
| static urqresult runscript(const char *exepath, const char *name) { |
| urqresult ur; |
| |
| ur= ensureoptions(); if (ur != urqr_normal) return ur; |
| ur=lockmethod(); if (ur != urqr_normal) return ur; |
| getcurrentopt(); |
| |
| if (coption) { |
| struct command cmd; |
| |
| strcpy(coption->meth->pathinmeth,exepath); |
| |
| command_init(&cmd, coption->meth->path, name); |
| command_add_args(&cmd, exepath, dpkg_db_get_dir(), |
| coption->meth->name, coption->name, NULL); |
| ur = falliblesubprocess(&cmd); |
| command_destroy(&cmd); |
| } else { |
| sthfailed("no access method is selected/configured"); |
| ur= urqr_fail; |
| } |
| pop_cleanup(ehflag_normaltidy); |
| |
| return ur; |
| } |
| |
| urqresult urq_update(void) { |
| return runscript(METHODUPDATESCRIPT,_("update available list script")); |
| } |
| |
| urqresult urq_install(void) { |
| return runscript(METHODINSTALLSCRIPT,_("installation script")); |
| } |
| |
| static urqresult rundpkgauto(const char *name, const char *dpkgmode) { |
| urqresult ur; |
| struct command cmd; |
| |
| command_init(&cmd, DPKG, name); |
| command_add_args(&cmd, DPKG, "--admindir", dpkg_db_get_dir(), "--pending", |
| dpkgmode, NULL); |
| |
| cursesoff(); |
| printf("running dpkg --pending %s ...\n",dpkgmode); |
| fflush(stdout); |
| ur = falliblesubprocess(&cmd); |
| command_destroy(&cmd); |
| |
| return ur; |
| } |
| |
| urqresult urq_remove(void) { |
| return rundpkgauto("dpkg --remove","--remove"); |
| } |
| |
| urqresult urq_config(void) { |
| return rundpkgauto("dpkg --configure","--configure"); |
| } |
| |
| urqresult urq_setup(void) { |
| quitaction qa; |
| urqresult ur; |
| |
| ur= ensureoptions(); if (ur != urqr_normal) return ur; |
| ur=lockmethod(); if (ur != urqr_normal) return ur; |
| getcurrentopt(); |
| |
| curseson(); |
| methodlist *l= new methodlist(); |
| qa= l->display(); |
| delete l; |
| |
| if (qa == qa_quitchecksave) { |
| struct command cmd; |
| |
| strcpy(coption->meth->pathinmeth,METHODSETUPSCRIPT); |
| |
| command_init(&cmd, coption->meth->path, _("query/setup script")); |
| command_add_args(&cmd, METHODSETUPSCRIPT, dpkg_db_get_dir(), |
| coption->meth->name, coption->name, NULL); |
| ur = falliblesubprocess(&cmd); |
| command_destroy(&cmd); |
| if (ur == urqr_normal) writecurrentopt(); |
| } else { |
| ur= urqr_fail; |
| } |
| |
| pop_cleanup(ehflag_normaltidy); |
| return ur; |
| } |