/* * at - at interface * * Copyright (C) 2009 Enrico Zini * * This program 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 program 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using GLib; namespace at { public struct Event { int id; time_t deadline; } // Return the earliest ID in the queue, or -1 if none are found // Queue is null for all queues, otherwise a queue name public static Event earliestID(string? queue = null) { Event res = { -1, 0 }; string argv[4]; argv[0] = "/usr/bin/atq"; if (queue == null) argv[1] = null; else { argv[1] = "-q"; argv[2] = queue; argv[3] = null; } Pid pid; int stdout; try { if (!Process.spawn_async_with_pipes("/", argv, null, SpawnFlags.STDERR_TO_DEV_NULL, null, out pid, null, out stdout, null)) return res; } catch (SpawnError e) { stderr.printf("Cannot run 'at -q': %s\n", e.message); return res; } FileStream fs = FileStream.fdopen(stdout, "r"); if (fs == null) return res; char buf[200]; string? line; while ((line = fs.gets(buf)) != null) { if (!line[0].isdigit()) continue; weak string rest; ulong id = line.to_ulong(out rest, 10); Time t = Time(); rest = t.strptime(rest.offset(1), "%a %b %d %H:%M:%S %Y"); if (rest == null) continue; if (rest.size() < 2) continue; //stderr.printf("PARSE QUEUE rest %s\n", rest); // Skip the queue of tasks currently being executed //if (rest[1] == '=') continue; // Skip entries not in the wanted queue if (queue != null && rest[1] != queue[0]) continue; time_t tt = t.mktime(); if (res.deadline == 0 || tt < res.deadline) { res.id = (int)id; res.deadline = tt; } } Process.close_pid(pid); return res; } public delegate bool jobParser(int fd); // Get the contents of a job given its id public static bool jobContents(int id, jobParser parser) { string argv[4]; argv[0] = "/usr/bin/at"; argv[1] = "-c"; argv[2] = id.to_string(); argv[3] = null; Pid pid; int stdoutfd; try { if (!Process.spawn_async_with_pipes("/", argv, null, SpawnFlags.STDERR_TO_DEV_NULL, null, out pid, null, out stdoutfd, null)) return false; } catch (SpawnError e) { stderr.printf("Cannot run 'at -c': %s\n", e.message); return false; } bool res = parser(stdoutfd); Process.close_pid(pid); return res; } /* TODO: schedule alarms via at Uses the 'z' queue. atq -q z can be used to list the jobs (for example, at startup, or after a job has run) at -c id can be used to query a job, parsing its contents (which can have comments or variables being set) zavai --notify ... can be used to notify the job (and start zavai if it's not running) Alarm needs to be able to serialize itself to an at invocation and to deserialize itself from the output of at -c Alarm needs to deserialize also a job with no special markers whatsoever: a generic at job. */ /* public class Alarm : Object { // TODO: make a factory method to construct from an "at -c" output // TODO: make a method that provides an at invocation public signal void trigger(Alarm a); public time_t deadline; public string label; public Alarm(time_t deadline, string label) { this.deadline = deadline; this.label = label; } } */ // Schedule a task that notifies a string // TODO public void schedule_label(const Alarm a); // Return the next item in the queue due to be run // TODO public Alarm? next_scheduled(); }