help.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. /*
  2. * dpkg - main program for package management
  3. * help.c - various helper routines
  4. *
  5. * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
  6. *
  7. * This is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2,
  10. * or (at your option) any later version.
  11. *
  12. * This is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public
  18. * License along with dpkg; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. #include <errno.h>
  22. #include <unistd.h>
  23. #include <dirent.h>
  24. #include <assert.h>
  25. #include <string.h>
  26. #include <sys/stat.h>
  27. #include <sys/types.h>
  28. #include <sys/wait.h>
  29. #include <signal.h>
  30. #include <config.h>
  31. #include <dpkg.h>
  32. #include <version.h>
  33. #include <dpkg-db.h>
  34. #include "filesdb.h"
  35. #include "main.h"
  36. const char *const statusstrings[]= {
  37. N_("not installed"), N_("unpacked but not configured"),
  38. N_("broken due to postinst failure"),
  39. N_("installed"),
  40. N_("broken due to failed removal"),
  41. N_("not installed but configs remain")
  42. };
  43. struct filenamenode *namenodetouse(struct filenamenode *namenode, struct pkginfo *pkg) {
  44. struct filenamenode *r;
  45. if (!namenode->divert) return namenode;
  46. debug(dbg_eachfile,"namenodetouse namenode=`%s' pkg=%s",
  47. namenode->name,pkg->name);
  48. r=
  49. (namenode->divert->useinstead && namenode->divert->pkg != pkg)
  50. ? namenode->divert->useinstead : namenode;
  51. debug(dbg_eachfile,
  52. "namenodetouse ... useinstead=%s camefrom=%s pkg=%s return %s",
  53. namenode->divert->useinstead ? namenode->divert->useinstead->name : "<none>",
  54. namenode->divert->camefrom ? namenode->divert->camefrom->name : "<none>",
  55. namenode->divert->pkg ? namenode->divert->pkg->name : "<none>",
  56. r->name);
  57. return r;
  58. }
  59. void checkpath(void) {
  60. /* Verify that some programs can be found in the PATH. */
  61. static const char *const checklist[]= {
  62. "ldconfig", "start-stop-daemon", "install-info", "update-rc.d", 0
  63. };
  64. struct stat stab;
  65. const char *const *clp;
  66. const char *path, *s, *p;
  67. char* buf;
  68. int warned= 0;
  69. long l;
  70. path= getenv("PATH");
  71. if (!path) fputs(_("dpkg - warning: PATH is not set.\n"), stderr);
  72. buf=(char*)m_malloc(strlen(path)+1);
  73. for (clp=checklist; *clp; clp++) {
  74. s= path;
  75. while (s) {
  76. p= strchr(s,':');
  77. l= p ? p-s : strlen(s);
  78. memcpy(buf,s,l);
  79. if (l) buf[l++]= '/';
  80. strcpy(buf+l,*clp);
  81. if (stat(buf,&stab) == 0 && (stab.st_mode & 0111)) break;
  82. s= p; if (s) s++;
  83. }
  84. if (!s) {
  85. fprintf(stderr,_("dpkg: `%s' not found on PATH.\n"),*clp);
  86. warned++;
  87. }
  88. }
  89. free(buf);
  90. if (warned)
  91. forcibleerr(fc_badpath,_("%d expected program(s) not found on PATH.\nNB: root's "
  92. "PATH should usually contain /usr/local/sbin, /usr/sbin and /sbin."),
  93. warned);
  94. }
  95. void ensure_package_clientdata(struct pkginfo *pkg) {
  96. if (pkg->clientdata) return;
  97. pkg->clientdata= nfmalloc(sizeof(struct pkginfoperfile));
  98. pkg->clientdata->istobe= itb_normal;
  99. pkg->clientdata->fileslistvalid= 0;
  100. pkg->clientdata->files= 0;
  101. }
  102. void cu_closepipe(int argc, void **argv) {
  103. int *p1= (int*)argv[0];
  104. close(p1[0]); close(p1[1]);
  105. }
  106. void cu_closefile(int argc, void **argv) {
  107. FILE *f= (FILE*)(argv[0]);
  108. fclose(f);
  109. }
  110. void cu_closedir(int argc, void **argv) {
  111. DIR *d= (DIR*)(argv[0]);
  112. closedir(d);
  113. }
  114. void cu_closefd(int argc, void **argv) {
  115. int *ip= (int*)(argv[0]);
  116. close(*ip);
  117. }
  118. int ignore_depends(struct pkginfo *pkg) {
  119. struct packageinlist *id;
  120. for (id= ignoredependss; id; id= id->next)
  121. if (id->pkg == pkg) return 1;
  122. return 0;
  123. }
  124. int force_depends(struct deppossi *possi) {
  125. return fc_depends ||
  126. ignore_depends(possi->ed) ||
  127. ignore_depends(possi->up->up);
  128. }
  129. int force_conflicts(struct deppossi *possi) {
  130. return fc_conflicts;
  131. }
  132. const char *pkgadminfile(struct pkginfo *pkg, const char *whichfile) {
  133. static struct varbuf vb;
  134. varbufreset(&vb);
  135. varbufaddstr(&vb,admindir);
  136. varbufaddstr(&vb,"/" INFODIR);
  137. varbufaddstr(&vb,pkg->name);
  138. varbufaddc(&vb,'.');
  139. varbufaddstr(&vb,whichfile);
  140. varbufaddc(&vb,0);
  141. return vb.buf;
  142. }
  143. static const char* preexecscript(const char *path, char *const *argv) {
  144. /* returns the path to the script inside the chroot
  145. * none of the stuff here will work if admindir isn't inside instdir
  146. * as expected. - fixme
  147. */
  148. int instdirl;
  149. if (*instdir) {
  150. if (chroot(instdir)) ohshite("failed to chroot to `%.250s'",instdir);
  151. }
  152. if (f_debug & dbg_scripts) {
  153. fprintf(stderr,"D0%05o: fork/exec %s (",dbg_scripts,path);
  154. while (*argv) fprintf(stderr," %s",*argv++);
  155. fputs(" )\n",stderr);
  156. }
  157. instdirl= strlen(instdir);
  158. if (!instdirl) return path;
  159. assert (strlen(path)>=instdirl);
  160. return path+instdirl;
  161. }
  162. static char *const *vbuildarglist(const char *scriptname, va_list ap) {
  163. static char *bufs[PKGSCRIPTMAXARGS+1];
  164. char *nextarg;
  165. int i;
  166. i=0;
  167. bufs[i++]= (char*)scriptname; /* yes, cast away const because exec wants it that way */
  168. for (;;) {
  169. assert(i < PKGSCRIPTMAXARGS);
  170. nextarg= va_arg(ap,char*);
  171. if (!nextarg) break;
  172. bufs[i++]= nextarg;
  173. }
  174. bufs[i]= 0;
  175. return bufs;
  176. }
  177. static char *const *buildarglist(const char *scriptname, ...) {
  178. char *const *arglist;
  179. va_list ap;
  180. va_start(ap,scriptname);
  181. arglist= vbuildarglist(scriptname,ap);
  182. va_end(ap);
  183. return arglist;
  184. }
  185. #define NSCRIPTCATCHSIGNALS sizeof(script_catchsignallist)/sizeof(int)-1
  186. static int script_catchsignallist[]= { SIGQUIT, SIGINT, 0 };
  187. static struct sigaction script_uncatchsignal[NSCRIPTCATCHSIGNALS];
  188. static void cu_restorescriptsignals(int argc, void **argv) {
  189. int i;
  190. for (i=0; i<NSCRIPTCATCHSIGNALS; i++) {
  191. if (sigaction(script_catchsignallist[i],&script_uncatchsignal[i],0)) {
  192. fprintf(stderr,_("error un-catching signal %s: %s\n"),
  193. strsignal(script_catchsignallist[i]),strerror(errno));
  194. onerr_abort++;
  195. }
  196. }
  197. }
  198. static void script_catchsignals(void) {
  199. int i;
  200. struct sigaction catchsig;
  201. onerr_abort++;
  202. memset(&catchsig,0,sizeof(catchsig));
  203. catchsig.sa_handler= SIG_IGN;
  204. sigemptyset(&catchsig.sa_mask);
  205. catchsig.sa_flags= 0;
  206. for (i=0; i<NSCRIPTCATCHSIGNALS; i++)
  207. if (sigaction(script_catchsignallist[i],&catchsig,&script_uncatchsignal[i]))
  208. ohshite(_("unable to ignore signal %s before running script"),
  209. strsignal(script_catchsignallist[i]));
  210. push_cleanup(cu_restorescriptsignals,~0, 0,0, 0);
  211. onerr_abort--;
  212. }
  213. static void setexecute(const char *path, struct stat *stab) {
  214. if ((stab->st_mode & 0555) == 0555) return;
  215. if (!chmod(path,0755)) return;
  216. ohshite(_("unable to set execute permissions on `%.250s'"),path);
  217. }
  218. int maintainer_script_installed(struct pkginfo *pkg, const char *scriptname,
  219. const char *description, ...) {
  220. /* all ...'s are const char*'s */
  221. const char *scriptpath, *scriptexec;
  222. char *const *arglist;
  223. struct stat stab;
  224. va_list ap;
  225. int c1;
  226. char buf[100];
  227. scriptpath= pkgadminfile(pkg,scriptname);
  228. va_start(ap,description);
  229. arglist= vbuildarglist(scriptname,ap);
  230. va_end(ap);
  231. sprintf(buf,"%s script",description);
  232. if (stat(scriptpath,&stab)) {
  233. if (errno == ENOENT) {
  234. debug(dbg_scripts,"maintainer_script_installed nonexistent %s",scriptname);
  235. return 0;
  236. }
  237. ohshite(_("unable to stat installed %s script `%.250s'"),description,scriptpath);
  238. }
  239. setexecute(scriptpath,&stab);
  240. c1= m_fork();
  241. if (!c1) {
  242. scriptexec= preexecscript(scriptpath,arglist);
  243. execv(scriptexec,arglist);
  244. ohshite(_("unable to execute %s"),buf);
  245. }
  246. script_catchsignals(); /* This does a push_cleanup() */
  247. waitsubproc(c1,buf,0);
  248. pop_cleanup(ehflag_normaltidy);
  249. ensure_diversions();
  250. return 1;
  251. }
  252. int maintainer_script_new(const char *scriptname, const char *description,
  253. const char *cidir, char *cidirrest, ...) {
  254. char *const *arglist;
  255. const char *scriptexec;
  256. struct stat stab;
  257. va_list ap;
  258. char buf[100];
  259. int c1;
  260. va_start(ap,cidirrest);
  261. arglist= vbuildarglist(scriptname,ap);
  262. va_end(ap);
  263. sprintf(buf,"%s script",description);
  264. strcpy(cidirrest,scriptname);
  265. if (stat(cidir,&stab)) {
  266. if (errno == ENOENT) {
  267. debug(dbg_scripts,"maintainer_script_new nonexistent %s `%s'",scriptname,cidir);
  268. return 0;
  269. }
  270. ohshite(_("unable to stat new %s script `%.250s'"),description,cidir);
  271. }
  272. setexecute(cidir,&stab);
  273. c1= m_fork();
  274. if (!c1) {
  275. scriptexec= preexecscript(cidir,arglist);
  276. execv(scriptexec,arglist);
  277. ohshite(_("unable to execute new %s"),buf);
  278. }
  279. script_catchsignals(); /* This does a push_cleanup() */
  280. waitsubproc(c1,buf,0);
  281. pop_cleanup(ehflag_normaltidy);
  282. ensure_diversions();
  283. return 1;
  284. }
  285. int maintainer_script_alternative(struct pkginfo *pkg,
  286. const char *scriptname, const char *description,
  287. const char *cidir, char *cidirrest,
  288. const char *ifok, const char *iffallback) {
  289. const char *oldscriptpath, *scriptexec;
  290. char *const *arglist;
  291. struct stat stab;
  292. int c1, n, status;
  293. char buf[100];
  294. pid_t r;
  295. oldscriptpath= pkgadminfile(pkg,scriptname);
  296. arglist= buildarglist(scriptname,
  297. ifok,versiondescribe(&pkg->available.version,
  298. vdew_nonambig),
  299. (char*)0);
  300. sprintf(buf,"old %s script",description);
  301. if (stat(oldscriptpath,&stab)) {
  302. if (errno == ENOENT) {
  303. debug(dbg_scripts,"maintainer_script_alternative nonexistent %s `%s'",
  304. scriptname,oldscriptpath);
  305. return 0;
  306. }
  307. fprintf(stderr,
  308. _("dpkg: warning - unable to stat %s `%.250s': %s\n"),
  309. buf,oldscriptpath,strerror(errno));
  310. } else {
  311. setexecute(oldscriptpath,&stab);
  312. c1= m_fork();
  313. if (!c1) {
  314. scriptexec= preexecscript(oldscriptpath,arglist);
  315. execv(scriptexec, arglist);
  316. ohshite(_("unable to execute %s"),buf);
  317. }
  318. script_catchsignals(); /* This does a push_cleanup() */
  319. while ((r= waitpid(c1,&status,0)) == -1 && errno == EINTR);
  320. if (r != c1) ohshite(_("wait for %s failed"),buf);
  321. pop_cleanup(ehflag_normaltidy);
  322. if (WIFEXITED(status)) {
  323. n= WEXITSTATUS(status); if (!n) return 1;
  324. fprintf(stderr, _("dpkg: warning - %s returned error exit status %d\n"),buf,n);
  325. } else if (WIFSIGNALED(status)) {
  326. n= WTERMSIG(status);
  327. fprintf(stderr, _("dpkg: warning - %s killed by signal (%s)%s\n"),
  328. buf, strsignal(n), WCOREDUMP(status) ? ", core dumped" : "");
  329. } else {
  330. ohshit(_("%s failed with unknown wait status code %d"),buf,status);
  331. }
  332. ensure_diversions();
  333. }
  334. fprintf(stderr, _("dpkg - trying script from the new package instead ...\n"));
  335. arglist= buildarglist(scriptname,
  336. iffallback,versiondescribe(&pkg->installed.version,
  337. vdew_nonambig),
  338. (char*)0);
  339. strcpy(cidirrest,scriptname);
  340. sprintf(buf,_("new %s script"),description);
  341. if (stat(cidir,&stab)) {
  342. if (errno == ENOENT)
  343. ohshit(_("there is no script in the new version of the package - giving up"));
  344. else
  345. ohshite(_("unable to stat %s `%.250s'"),buf,cidir);
  346. }
  347. setexecute(cidir,&stab);
  348. c1= m_fork();
  349. if (!c1) {
  350. scriptexec= preexecscript(cidir,arglist);
  351. execv(scriptexec, arglist);
  352. ohshite(_("unable to execute %s"),buf);
  353. }
  354. script_catchsignals(); /* This does a push_cleanup() */
  355. waitsubproc(c1,buf,0);
  356. pop_cleanup(ehflag_normaltidy);
  357. fprintf(stderr, _("dpkg: ... it looks like that went OK.\n"));
  358. ensure_diversions();
  359. return 1;
  360. }
  361. void clear_istobes(void) {
  362. struct pkgiterator *it;
  363. struct pkginfo *pkg;
  364. it= iterpkgstart();
  365. while ((pkg= iterpkgnext(it)) != 0) {
  366. ensure_package_clientdata(pkg);
  367. pkg->clientdata->istobe= itb_normal;
  368. pkg->clientdata->replacingfilesandsaid= 0;
  369. }
  370. }
  371. void debug(int which, const char *fmt, ...) {
  372. va_list ap;
  373. if (!(f_debug & which)) return;
  374. fprintf(stderr,"D0%05o: ",which);
  375. va_start(ap,fmt);
  376. vfprintf(stderr,fmt,ap);
  377. va_end(ap);
  378. putc('\n',stderr);
  379. }
  380. int isdirectoryinuse(struct filenamenode *file, struct pkginfo *pkg) {
  381. /* Returns 1 if the file is used by packages other than pkg, 0 otherwise. */
  382. struct filepackages *packageslump;
  383. int i;
  384. debug(dbg_veryverbose, "isdirectoryinuse `%s' (except %s)", file->name,
  385. pkg ? pkg->name : "<none>");
  386. for (packageslump= file->packages; packageslump; packageslump= packageslump->more) {
  387. debug(dbg_veryverbose, "isdirectoryinuse packageslump %s ...",
  388. packageslump->pkgs[0] ? packageslump->pkgs[0]->name : "<none>");
  389. for (i=0; i < PERFILEPACKAGESLUMP && packageslump->pkgs[i]; i++) {
  390. debug(dbg_veryverbose, "isdirectoryinuse considering [%d] %s ...", i,
  391. packageslump->pkgs[i]->name);
  392. if (packageslump->pkgs[i] == pkg) continue;
  393. return 1;
  394. }
  395. }
  396. debug(dbg_veryverbose, "isdirectoryinuse no");
  397. return 0;
  398. }
  399. void oldconffsetflags(struct conffile *searchconff) {
  400. struct filenamenode *namenode;
  401. while (searchconff) {
  402. namenode= findnamenode(searchconff->name);
  403. namenode->flags |= fnnf_old_conff;
  404. debug(dbg_conffdetail, "oldconffsetflags `%s' namenode %p flags %o",
  405. searchconff->name, namenode, namenode->flags);
  406. searchconff= searchconff->next;
  407. }
  408. }
  409. int chmodsafe_unlink(const char *pathname) {
  410. struct stat stab;
  411. if (lstat(pathname,&stab)) return -1;
  412. if (S_ISREG(stab.st_mode) ? (stab.st_mode & 07000) :
  413. !(S_ISLNK(stab.st_mode) || S_ISDIR(stab.st_mode) ||
  414. S_ISFIFO(stab.st_mode) || S_ISSOCK(stab.st_mode))) {
  415. /* We chmod it if it is 1. a sticky or set-id file, or 2. an unrecognised
  416. * object (ie, not a file, link, directory, fifo or socket
  417. */
  418. if (chmod(pathname,0600)) return -1;
  419. }
  420. if (unlink(pathname)) return -1;
  421. return 0;
  422. }
  423. void ensure_pathname_nonexisting(const char *pathname) {
  424. int c1;
  425. const char *u;
  426. u= skip_slash_dotslash(pathname);
  427. assert(*u);
  428. debug(dbg_eachfile,"ensure_pathname_nonexisting `%s'",pathname);
  429. if (!rmdir(pathname)) return; /* Deleted it OK, it was a directory. */
  430. if (errno == ENOENT || errno == ELOOP) return;
  431. if (errno == ENOTDIR) {
  432. /* Either it's a file, or one of the path components is. If one
  433. * of the path components is this will fail again ...
  434. */
  435. if (!chmodsafe_unlink(pathname)) return; /* OK, it was */
  436. if (errno == ENOTDIR) return;
  437. }
  438. if (errno != ENOTEMPTY) /* Huh ? */
  439. ohshite(_("failed to rmdir/unlink `%.255s'"),pathname);
  440. c1= m_fork();
  441. if (!c1) {
  442. execlp(RM,"rm","-rf","--",pathname,(char*)0);
  443. ohshite(_("failed to exec rm for cleanup"));
  444. }
  445. debug(dbg_eachfile,"ensure_pathname_nonexisting running rm -rf");
  446. waitsubproc(c1,"rm cleanup",0);
  447. }
  448. void check_libver (void) {
  449. int c;
  450. if (!strcmp(DPKG_VERSION, libdpkgver())) return;
  451. /* ooh, we have a version mismatch with the library,
  452. * continue, but warn LOUDLY about possible problems.
  453. */
  454. fprintf(stderr, _("\
  455. WARNING: A mismatch between dpkg and libdpkg.so has\n\
  456. been detected. Somehow, your system has a different\n\
  457. version of dpkg than the library that is uses. This\n\
  458. may not cause any problems, but it does reflect a\n\
  459. serious condition. You should really reinstall the dpkg\n\
  460. package before continuing.\n\
  461. \n\
  462. Press 'Q' to exit, any other key to continue: "));
  463. c= getc(stdin);
  464. if (c == 'q' || c == 'Q')
  465. ohshite(_("Quitting at user request"));
  466. return;
  467. }