mirror of
https://github.com/knutwurst/patchdl.git
synced 2026-10-06 13:00:21 +02:00
Cancel a running download (the worker aborts mid-piece and the partial file is removed) or delete a finished package, from the queue or the title card. The progress callback now returns an abort signal that reaches libcurl and the manifest merge loop. Manifest merge: bound the piece scan to the "pieces" array so a later "url" key (e.g. playgoChunkCrcUrl) can't be appended as a bogus piece, and require each piece's fileOffset to match the bytes written so far so an out-of-order manifest fails instead of silently producing a corrupt package. Report real free space on the download partition via statvfs; it was a hardcoded 0. Fixes found in review: - scan: bound the SFO entry table to the bytes actually read and require the key to be NUL-terminated before strcmp (OOB read on a crafted param.sfo from a shadow-mounted dir). - proc: bound the kinfo_proc walk and the name compare to the record and the buffer. - install: publish the API probe under the lock (data race with the MHD worker thread) and initialize rc2. - verxml: reject a truncated attribute value instead of returning it as valid. - web: keep download/install/downloaded flags across a refresh, stop the queue poll only after repeated empty results, coerce the progress number, and treat a cancelled download (HTTP 200, ok:false) as not-downloaded.
76 lines
2.2 KiB
C
76 lines
2.2 KiB
C
#include "patchdl_proc.h"
|
|
|
|
#include <signal.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/syscall.h>
|
|
#include <sys/sysctl.h>
|
|
|
|
/* kinfo_proc field offsets for the FreeBSD 9-based PS5 kernel.
|
|
Same layout used by ps5-payload-dev/ftpsrv (verified on fw 11.60):
|
|
ki_pid at +72, ki_tdname (thread name) at +447, ki_structsize at +0. */
|
|
#define KINFO_OFF_STRUCTSIZE 0
|
|
#define KINFO_OFF_PID 72
|
|
#define KINFO_OFF_TDNAME 447
|
|
|
|
void
|
|
patchdl_proc_set_name(const char *name) {
|
|
/* tid -1 = current thread */
|
|
syscall(SYS_thr_set_name, -1, name);
|
|
}
|
|
|
|
static pid_t
|
|
find_pid(const char *name) {
|
|
int mib[4] = {1, 14, 8, 0}; /* CTL_KERN, KERN_PROC, KERN_PROC_ALL */
|
|
pid_t mypid = getpid();
|
|
pid_t pid = -1;
|
|
size_t buf_size;
|
|
uint8_t *buf;
|
|
|
|
if (sysctl(mib, 4, 0, &buf_size, 0, 0)) return -1;
|
|
if (!(buf = malloc(buf_size))) return -1;
|
|
if (sysctl(mib, 4, buf, &buf_size, 0, 0)) { free(buf); return -1; }
|
|
|
|
/* The loop guard guarantees the structsize/pid/tdname fields are inside the
|
|
buffer before we read them, and the per-record check below keeps the name
|
|
compare within the record (and thus the buffer). */
|
|
for (uint8_t *ptr = buf; ptr + KINFO_OFF_TDNAME < buf + buf_size; ) {
|
|
int ki_structsize = *(int *)(ptr + KINFO_OFF_STRUCTSIZE);
|
|
pid_t ki_pid;
|
|
char *ki_tdname;
|
|
size_t name_max;
|
|
|
|
if (ki_structsize <= KINFO_OFF_TDNAME) break; /* malformed/truncated */
|
|
if (ptr + ki_structsize > buf + buf_size) break; /* record past buffer */
|
|
|
|
ki_pid = *(pid_t *)(ptr + KINFO_OFF_PID);
|
|
ki_tdname = (char *)(ptr + KINFO_OFF_TDNAME);
|
|
name_max = (size_t)(ptr + ki_structsize - (uint8_t *)ki_tdname);
|
|
|
|
if (!strncmp(name, ki_tdname, name_max) && ki_pid != mypid)
|
|
pid = ki_pid;
|
|
|
|
ptr += ki_structsize;
|
|
}
|
|
|
|
free(buf);
|
|
return pid;
|
|
}
|
|
|
|
int
|
|
patchdl_proc_kill_others(const char *name) {
|
|
int killed = 0;
|
|
pid_t pid;
|
|
|
|
while ((pid = find_pid(name)) > 0) {
|
|
if (kill(pid, SIGKILL))
|
|
break;
|
|
killed++;
|
|
sleep(1); /* let the port + process slot free up */
|
|
}
|
|
return killed;
|
|
}
|